W Accessie kwerenda wstawiająca nowe wartości do tabeli generuje wyrażenie SQL, które wygląda następująco:



Podobne dokumenty
PL/SQL. Funkcje wbudowane

Wykład III. dr Artur Bartoszewski Wydział Nauczycielski, Kierunek Pedagogika Wprowadzenie do baz danych

Materiały do laboratorium MS ACCESS BASIC

Aplikacje w środowisku VBA. Visual Basic for Aplications

Zastanawiałeś się może, dlaczego Twój współpracownik,

Przewodnik Szybki start

BAZY DANYCH Panel sterujący

5. Bazy danych Base Okno bazy danych

Materiały pomocnicze do zajęć z przedmiotu Projekt ADP

2. Kliknij Insert->Userform. Jeżeli Toolbox nie pojawi się automatycznie, kliknij View -> Toolbox. Otrzymany widok powinien być jak poniżej.

Uwagi dotyczące notacji kodu! Moduły. Struktura modułu. Procedury. Opcje modułu (niektóre)

LABORATORIUM 8,9: BAZA DANYCH MS-ACCESS

DECLARE VARIABLE zmienna1 typ danych; BEGIN

BAZY DANYCH Formularze i raporty

UNIWERSYTET RZESZOWSKI KATEDRA INFORMATYKI

Administracja i programowanie pod Microsoft SQL Server 2000

1. Zarządzanie informacją w programie Access

Zapytania i wstawianie etykiet z bazy danych do rysunku

Przygotowanie własnej procedury... 3 Instrukcja msgbox wyświetlanie informacji w oknie... 6 Sposoby uruchamiania makra... 8

Kwerenda. parametryczna, z polem wyliczeniowym, krzyżowa

SQL (ang. Structured Query Language)

Wybierz polecenie z menu: Narzędzia Listy i dokumenty

Wprowadzenie do programowania w języku Visual Basic. Podstawowe instrukcje języka

Makra Access 2003 wg WSiP Wyszukiwanie, selekcjonowanie i gromadzenie informacji Ewa Mirecka

Bazy danych kwerendy (moduł 5) 1. Przekopiuj na dysk F:\ bazę M5KW.mdb z dysku wskazanego przez prowadzącego

Instrukcja podwaja zarobki osób, których imiona zaczynają się P i dalsze litery alfabetu zakładamy, że takich osbób jest kilkanaście.

CZĘŚĆ A PIERWSZE KROKI Z KOMPUTEREM

Oracle PL/SQL. Paweł Rajba.

16) Wprowadzenie do raportowania Rave

Wykład II. dr Artur Bartoszewski Wydział Nauczycielski, Kierunek Pedagogika Wprowadzenie do baz danych

DAO. tworzenie tabeli

Tworzenie bazy danych na przykładzie Access

Access - Aplikacja. Tworzenie bazy danych w postaci aplikacji

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody

LK1: Wprowadzenie do MS Access Zakładanie bazy danych i tworzenie interfejsu użytkownika

MS Access formularze

Zakres tematyczny dotyczący podstaw programowania Microsoft Office Excel za pomocą VBA

Oracle Application Express

Automatyzowanie zadan przy uz yciu makr języka Visual Basic

Pakiety są logicznymi zbiorami obiektów takich jak podprogramy, typy, zmienne, kursory, wyjątki.

Formularze w programie Word

Systemy GIS Tworzenie zapytań w bazach danych

Korespondencja seryjna

Microsoft Access zajęcia 3 4. Tworzenie i wykorzystanie kwerend, formularzy i raportów

Paweł Rajba

Autor: Joanna Karwowska

Makra programu Microsoft Access.

Cel: Przypisujemy przyciskom określone funkcje panel górny (Panel1)

Edytor materiału nauczania

Oracle PL/SQL. Paweł Rajba.

Baza danych. Program: Access 2007

Wstęp 7 Rozdział 1. OpenOffice.ux.pl Writer środowisko pracy 9

PODSTAWY BAZ DANYCH 13. PL/SQL

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Kiedy i czy konieczne?

Rozwiązanie. Uruchom program Access 2007.

15. Funkcje i procedury składowane PL/SQL

1. Przekopiuj na dysk F bazę M5BIB.mdb z dysku wskazanego przez prowadzącego 2. Otwórz bazę (F:\M5BIB.mdb)

Wprowadzenie (17) Część I. Makra w Excelu - podstawy (23)

ACCESS ćwiczenia (zestaw 1)

5.3. Tabele. Tworzenie tabeli. Tworzenie tabeli z widoku projektu. Rozdział III Tworzenie i modyfikacja tabel

Wyzwalacze. do automatycznego generowania wartości kluczy głównych. Składnia instrukcji tworzacej wyzwalacz

Arkusz kalkulacyjny EXCEL

Projekt ZSWS. Instrukcja uŝytkowania narzędzia SAP Business Explorer Analyzer. 1 Uruchamianie programu i raportu. Tytuł: Strona: 1 z 31

Programowanie strukturalne. Opis ogólny programu w Turbo Pascalu

Pakiety podprogramów Dynamiczny SQL

Wprowadzania liczb. Aby uniknąć wprowadzania ułamka jako daty, należy poprzedzać ułamki cyfrą 0 (zero); np.: wpisać 0 1/2

AUTOMATYZACJA PRACY Z UŻYCIEM MAKR. Tom XII NPV WSP.KORELACJI ROZKŁ.EXP JEŻELI COS KOMÓRKA VBA DNI.ROBOCZE ILOCZYN LOG SUMA CZY.

Dokumentacja programu. Zoz. Uzupełnianie kodów terytorialnych w danych osobowych związanych z deklaracjami POZ. Wersja

Laboratorium - Monitorowanie i zarządzanie zasobami systemu Windows XP

Korespondencja seryjna

Zadanie 1. Stosowanie stylów

MODUŁ INTEGRUJĄCY ELEKTRONICZNEGO NADAWCĘ Z WF-MAG SPIS TREŚCI

Bloki anonimowe w PL/SQL

WPROWADZANIE ZLECEŃ POPRZEZ STRONĘ INSTRUKCJA UŻYTKOWNIKA

Korespondencja seryjna Word 2000

Konspekt do lekcji informatyki dla klasy II gimnazjum. TEMAT(1): Baza danych w programie Microsoft Access.

1. MS Access opis programu.

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości

Manipulowanie danymi przy użyciu DAO

Formatowanie tekstu przy uz yciu stylo w

LABORATORIUM 6: ARKUSZ MS EXCEL JAKO BAZA DANYCH

5.5. Wybieranie informacji z bazy

1. Przypisy, indeks i spisy.

DECLARE <nazwa_zmiennej> typ [(<rozmiar> )] [ NOT NULL ] [ { := DEFAULT } <wartość> ];

Wymagania edukacyjne z informatyki dla klasy szóstej szkoły podstawowej.

Wykład I. dr Artur Bartoszewski Wydział Nauczycielski, Kierunek Pedagogika Wprowadzenie do baz danych

PRZESTRZENNE BAZY DANYCH WYKŁAD 2

Funkcje. Rozdział 3a Funkcje wierszowe. Funkcje znakowe (1) Funkcje wierszowe

Trigger jest obiektem związanym z tablicą, który aktywuje się gdy do tablicy następuje odpowiednie zapytanie.

Rys.1. Uaktywnianie pasków narzędzi. żądanych pasków narzędziowych. a) Modelowanie części: (standardowo widoczny po prawej stronie Przeglądarki MDT)

LibreOffice Calc VBA

Dodawanie grafiki i obiektów

Visual Basic for Applications. Wstęp

IIIIIIIIIIIIIIIMMIMMIII

Stosowanie, tworzenie i modyfikowanie stylów.

Nawigacja po długim dokumencie może być męcząca, dlatego warto poznać następujące skróty klawiszowe

System Obsługi Zleceń

Dodawanie operacji dodatkowych w WAPRO Mag.

Praca z wynikami w ALOORA

Transkrypt:

301 Rozdział 17. Interfejs Access a 2000 do Oracle a SELECT * FROM emp WHERE comm IS NULL SELECT * FROM emp WHERE comm IS NOT NULL Tworzenie wyrażeń Insert W Accessie kwerenda wstawiająca nowe wartości do tabeli generuje wyrażenie SQL, które wygląda następująco: INSERT INTO SCOTT_EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, DEPTNO) SELECT '9999' AS Expr1, 'JP' AS Expr2, 'SALESMAN' AS Expr3, _ 7698 AS Expr4, #7/27/1997# AS Expr5, 2380 AS Expr6, 10 AS Expr7; Jednak Access dopuszcza klauzulę Values tak samo jak Oracle (patrz poniżej), ale musisz ją wpisać samemu. W Oracle'u możesz uprościć to wyrażenie: INSERT INTO SCOTT_EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, _ COMM, DEPTNO) VALUES ('9999', 'JP', 'SALESMAN', 7698, _ TO_DATE('7/27/1997', 'MM/DD/YYYY'), 2380, 0, 10) Zwróć uwagę jak w Oracle'u używa się To_Date(), aby sprawdzić, czy wpisana data jest prawidłowa. Więcej o tej i innych funkcjach Oracle'a napisałem w dalszej części rozdziału. Tworzenie wyrażeń Update Implementacja wyrażenia Update w SQL Oracle nie różni się wiele od tej z Accessa. Poniżej przedstawione jest wyrażenie SQL, wygenerowane przez QBE Accessa, skojarzone z tabelą połączoną. UPDATE SCOTT_EMP SET SCOTT_EMP.SAL = [7000] WHERE ((([SCOTT_EMP].[EMPNO])=9999)); Wersja dla Oracle'a jest prostsza od wersji Accessa o kilka nawiasów. Ponieważ ODBC wysyła ciąg ODBC bezpośrednio do tabel użytkownika Scott, nie ma potrzeby kwalifikować nazw tabel nazwą użytkownika. UPDATE emp SET SAL = 7000 WHERE empno=9999 Użycie Group By/Having QBE Accessa samo troszczy się o prawidłową składnię, gdy tworzysz kwerendę grupującą. W Oracle'u musisz sam się tym zająć zająć. Tak jak w Accessie, Group By grupuje dane w wymienionych kolumnach. Wszystkie inne kolumny muszą być przeglądane poprzez funkcje agregujące (np.: Sum(), Avg() i inne). SELECT deptno, count(*) FROM emp WHERE deptno<>10 GROUP BY deptno HAVING count(*)<6 Podczas wykonania powyższego wyrażenia Oracle pobierze wszystkie rekordy z wartością pola deptno różną od 10 i grupuje je według pola wymienionego w operacji GROUP BY. Na koniec Oracle przeszukuje rezultat i odrzuca rekordy, których liczba (count(*)) jest większa od 6. Jedyną różnicą pomiędzy tym wyrażeniem SQL a wyrażeniem w SQL Accessa jest występowanie nawiasów. Funkcje w Oracle'u i Accessie W Accessie, przed wykonaniem kwerendy jest ona przeszukiwana pod kątem występowania funkcji zarówno VBA, jak i utworzonych przez Ciebie. Analizator wyrażeń (ang. Jet Expression Service) dopuszcza stosowanie dowolnych funkcji w wyrażeniach SQL. Nie możesz jednak stosować funkcji VBA oraz napisanych przez siebie, gdy używasz kwerend SPT. Powód jest prosty, SPT nie używa w ogóle silnika Jet. Oracle odbiera SQL jako ciąg znaków i musi on być zrozumiały dla Oracle'a. Mimo że jest możliwe utworzenie w Oracle'u podobnego zestawu funkcji jak w Accessie, wykracza to jednak poza ramy tego rozdziału. W dalszej części rozdziału zrobimy przegląd niektórych, najczęściej używanych funkcji Oracle'a, które możesz użyć w kwerendach przekazujących. Wiele z funkcji udostępnianych przez Oracle jest bardzo podobnych do funkcji operujących na ciągach w Accessie. Poniżej przedstawię funkcje, które nie istnieją w Accessie, lub działają inaczej niż podobne do nich. Aby uzyskać pełną listę funkcji, sięgnij do dokumentacji Oracle'a.

Część V Access i architektura klient-serwer 302 Ciągi Łączenie Większość typów danych, z którymi się spotykasz, to ciągi lub takie, które da się zamienić na ciągi. Zwykle będziesz chciał przeszukiwać ciągi znaków, analizować je, zmieniać wielkość liter, łączyć lub inaczej mówiąc zmieniać je tak, aby pasowały do twoich formularzy i raportów. W tej części opiszę niektóre z powszechnie używanych operacji na ciągach znaków, które będziesz chciał wykonać w Oracle'u. Oracle łączy ciągi znaków przy użyciu dwóch pionowych kresek ( ) w odróżnieniu od Accessa, w którym używa się znaku & lub +. Poniższe wyrażenie przedstawia w jaki sposób, łączyć ciągi. SELECT ename deptno FROM emp Initcap, Lower, Upper Funkcja Initcap(string) zmienia na wileką pierwszą literę każdego wyrazu ciągu. Podobnie Upper i Lower zmienia wszystkie litery ciągu na odpowiednio wielkie i małe. Select INITCAP(ename) FROM emp Zwróci następujący wynik: INITCAP(ENAME) ---------- Jp Allen Ward Jones Martin Blake Clark Scott King Turner Adams James Ford Miller SELECT UPPER(ENAME) FROM emp Zwróci następujący wynik: UPPER(ENAME) ---------- JP ALLEN WARD JONES MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER SELECT LOWER(ename) FROM emp Zwróci następujący wynik: LOWER(ENAME) ---------- jp allen ward jones martin blake clark scott king turner adams

303 Rozdział 17. Interfejs Access a 2000 do Oracle a james ford miller Instr Instr zwraca pozycję znaku, który podałeś jako argument i może być bardzo przydatna, jeżeli chcesz analizować ciągi, poszukując przecinków lub spacji. Jeżeli poszukiwany znak nie występuje w ciągu, zwracana jest wartość 0. Funkcja Instr jest wrażliwa na wielkość liter w odróżnieniu od Accessa. Instr ma cztery parametry: String wymagany. Ciąg znaków lub odwołanie do ciągu, który chcesz przeszukać. Set wymagany. Znak lub ciąg znaków, które chcesz znaleźć. Start nieobowiązkowy. Pozycja, na której powinno się rozpocząć szukanie. Domyślnie jest to pierwsza pozycja. Occurrence nieobowiązkowy. Jeżeli chcesz znaleźć drugie lub trzecie wystąpienie parametru Set, wpisz 2 lub 3. Popatrz na wyrażenie SQL, w którym nie podamy wystąpienia ani pozycji startowej: Select ename, instr(ename, 'A') from emp Wynik: LTrim/RTrim ENAME INSTR(ENAME,'A') ---------- ---------------- JP 0 ALLEN 1 WARD 2 JONES 0 MARTIN 2 BLAKE 3 CLARK 3 SCOTT 0 KING 0 TURNER 0 ADAMS 1 JAMES 2 FORD 0 MILLER 0 Gdy funkcja zostanie wywołana z parametrem Occurence równym 2, znajdzie drugie wystąpienie szukanego znaku. Select ename, instr(ename, 'A') from enp ENAME INSTR(ENAME,'A') ---------- ---------------- JP 0 ALLEN 0 WARD 0 JONES 0 MARTIN 0 BLAKE 0 CLARK 0 SCOTT 0 KING 0 TURNER 0 ADAMS 3 JAMES 0 FORD 0 MILLER 0 Access ma trzy funkcje do wycinania znaków z ciągu: LTrim(), aby usunąć znaki z lewej strony, Rtrim, aby usunąć znaki z prawej strony oraz Trim, aby usunąć znaki z obu stron. Oracle ma tylko Ltrim i Rtrim. Jednak funkcje obcinające znaki w Accessie i Oracle'u różnią się w inny, bardzo ważny sposób. W Accessie funkcje te obcinają tylko spacje, w Oracle'u mogą obcinać dowolny zbiór znaków. Funkcje obcinające mają dwa argumenty: String wymagany. Ciąg lub odwołanie do ciągu, na którym chcesz wykonać operacje. Set nieobowiązkowy. Znaki, które chcesz usunąć.

Część V Access i architektura klient-serwer 304 Możesz użyć funkcji LTrim/RTrim, aby usunąć słowo 'THE' z początku tytułów poprzez wykonanie następującego wyrażenia: Select LTrim(Title, '"THE ') from Books Należy pamiętać, że funkcje RTrim/LTrim są niewrażliwe na wielkość liter i ignorują kolejność podanych znaków do usunięcia. Oznacza to, że tytuły książek zostaną zmienione w sposób pokazany w tabeli 17.2. Tabela 17.2. Przed i po obcięciu funkcją LTrim Przed The Great Access Book How to Develop in Access The Ethical Developer Access 2000 Development Unleashed Po obcięciu Great Access Book Ow to Develop in Access ical Developer Access 2000 Development Unleashed Soundex Substr Funkcje LTrim/RTrim nie zwracają uwagi na kolejność liter w zbiorze liter do usunięcia ani na to, że powtarza ją się kilka razy (tak jak: THE ETH... w The Ethical Developer). Aby uzyskać prawidłowe wyniki powinieneś prawdopodobnie użyć kombinacji tej funkcji z Instr, Substr i Decode, aby dostać wyniki, jakich naprawdę potrzebujesz. Od roku 1988 Census Bureau używa algorytmu klasyfikacji nazwisk, które są podobnie wymawiane (w języku angielskim). Algorytm ten nazywany jest Soundex. Działa on przez pobranie pierwszej litery i przypisanie liczby do każdej następnej spółgłoski. Różne spółgłoski mają przyporządkowane te same wartości (na przykład [T] i [D] są tłumaczone na 3), oparte o ich brzmienie. Proces ten jest powtarzany aż do skompletowania 4. cyfrowego kodu. Słowa, które mają za mało spółgłosek są uzupełniane zerami tak, aby wygenerować czteroznakowy kod. Samogłoski są odrzucane, chyba że jest ona pierwszym znakiem w słowie. Kody Soundex wyglądają następująco: Select ename, soundex(ename) from emp ENAME SOUNDEX(ENAME) ---------- -------------- JP J100 ALLEN A450 WARD W630 JONES J520 MARTIN M635 BLAKE B420 CLARK C462 SCOTT S300 KING K520 TURNER T656 ADAMS A352 JAMES J520 FORD F630 MILLER M460 Soundex może być użyteczny do wyszukiwania nazwisk w listach lub tytułach. Wyrażenie SQL takie jak poniżej: Select ename from emp where soundex(ename) like soundex('muller') powinno zwrócić nazwiska takie jak: Mailer Miller Molar Moller Muler Mulronsky Funkcja Soundex nie interpretuje kontekstu znaków, więc niektóre wyniki mogą nie być intuicyjne na pierwszy rzut oka. Słowa o różnej długości mogą sobie odpowiadać według tego algorytmu. Mimo tych niedogodności można go użyć do przeszukiwania list wysyłkowych i książek telefonicznych. Substr można porównać do funkcji Mid w Accessie. Oracle nie ma bezpośredniego odpowiednika funkcji Right() i Left() znanych z Accessa. Tak jak funkcja Accessa Mid(), Substr() pobiera trzy argumenty: String ciąg lub odwołanie do ciągu

305 Rozdział 17. Interfejs Access a 2000 do Oracle a Start podana jawnie lub obliczona pozycja początku podciągu End podana jawnie lub obliczona wartość reprezentująca ilość znaków po prawej stronie pozycji Start W sytuacjach, kiedy nazwisko klienta występuje w postaci: MacIntyre, Alastair możesz użyć funkcji Substr() w połączeniu z Instr(), aby rozdzielić nazwisko na osobne pola. SUBSTR(CustomerName, INSTR(CustomerName, ', ')+2) = Alastair SUBSTR(CustomerName, 1, INSTR(CustomerName, ', ')-1) = MacIntyre W pierwszym wypadku Substr pobierze wszystkie znaki z ciągu, zaczynając od drugiego znaku po znaku, aż do końca ciągu. Pozostawienie trzeciego argumentu pustego spowoduje, że funkcja przyjmie go równego długości całego ciągu. W drugim przypadku funkcja zwróci wszystkie znaki od początku ciągu aż do znaku poprzedzającego przecinek. Decode Wielu programistów Accessa przyzwyczaiło się opierać na natychmiastowym porównaniu (IIf()) w swoich kwerendach. Oracle nie dostarcza podobnie nazywającej się funkcji, można za to użyć podobnie działającej funkcji Decode. Decode jest serią testów If/Then zakończonych przez Else. To oznacza, że jest to raczej konstrukcja typu Case Select niż IIf(). DECODE( value, if1, then1, if2, then2,..., else) Ilość konstrukcji if/then jest prawie nieograniczona. Poniższe wyrażenie SQL jest prostym przykładem użycia funkcji Decode do zamiany nazw miast na regiony, w których leżą: Select loc, DECODE(loc, 'NEW YORK', 'MID-ATLANTIC', 'DALLAS', 'SOUTH', BOSTON', 'NEW ENGLAND', 'CHICAGO', 'MIDWEST', 'UNKNOWN') REGION FROM dept Wynik tej kwerendy przedstawia, w jaki sposób zostały pokazane regiony i w jaki sposób obsłużone zostało nieznane miasto przez część Else funkcji Decode. Select loc, DECODE(loc, 'NEW YORK', 'MID-ATLANTIC', 'DALLAS', 'SOUTH', BOSTON', 'NEW ENGLAND', 'CHICAGO', 'MIDWEST', 'UNKNOWN') As REGION FROM dept LOC REGION ---------- ------------ NEW YORK MID-ATLANTIC DALLAS SOUTH CHICAGO MIDWEST BOSTON NEW ENGLAND SUMMIT UNKNOWN Obliczenia w Oracle'u Ceil() Floor() Dopóki dobry projekt struktury bazy nie będzie przechowywać większości wyników obliczeń, nie będziesz mógł tworzyć sensownych interfejsów lub raportów bez poznania funkcji matematycznych Oracle'a. Funkcje Oracle'a są bardzo podobne do tych, które występowały w VBA lub Accessie. Rozdział ten wskaże kilka różnic pomiędzy funkcjami Oracle'a i Accessa. Ceil() nie ma odpowiednika w Accessie. Zwraca on najbliższą liczbę całkowitą większą lub równą wartości zadanej. CEIL(34.2) = 35 CEIL( -2.4) = -2 Floor() jest przeciwnością Ceil(), także nie mającą odpowiednika w Accessie. Funkcja zwraca najbliższą liczbę całkowitą mniejszą lub równą wartości zadanej jako argument. Floor(34.2) = 34 Floor( -2.4 ) = -3

Część V Access i architektura klient-serwer 306 Nvl() Round() Sign() Trunc() Greatest/Least Funkcja Nvl() jest funkcją podstawiania wartości i jest podobna do funkcji NZ() w VBA. Umożliwia ona podstawienie zadanej wartości, gdy argument jest wartością null. Pomaga ona zapobiegać błędom matematycznym spowodowanym przez podstawienie wartości null do obliczeń. Posiada ona dwa parametry: Value wymagana. Wartość lub odwołanie do wartości. Substitute wymagana. Wartość zwracana przez funkcję, gdy Value będzie null. NVL(wartość, podstawienie) NVL(238, 15)=238 NVL(null, 15)=15 W Accessie przez długi czas brakowało funkcji Round(). W Accessie 2000 użytkownicy nareszcie mogą z niej skorzystać. Funkcja ma dwa parametry: Value wymagana. Wartość lub odwołanie do wartości do przetworzenia. Precision nieobowiązkowa. Ilość miejsc po przecinku, do ilu będzie zaokrąglana liczba. Domyślnie przyjmowane jest zero. Sign() działa dokładnie tak jak funkcja Accessa Sgn(). Zwraca ona 1 dla liczb dodatnich i -1 dla ujemnych. Zamiast zaokrąglać liczbę w górę lub w dół, Trunc() po prostu obcina liczbę do żądanej długości. Funkcja posiada dwa parametry: Value wymagana. Wartość lub odwołanie do wartości do przetworzenia. Precision nieobowiązkowa. Ilość miejsc po przecinku, do ilu będzie obcięta liczba. Domyślnie przyjmowane jest zero. Greatest i Least używane są, aby wybrać pomiędzy dwiema lub więcej wartościami. Mogą być one użyte do liczb, ciągów lub dat. Gdy używane są do porównywania dat, jak w tym przykładzie poniżej, daty podawane w postaci tekstu muszą być konwertowane przez funkcję To_Date(), w przeciwnym wypadku zostaną potraktowane jako ciąg znaków i wynik funkcji nie będzie taki, jakiego się spodziewamy. W przykładzie użyta jest funkcja Least, aby wybrać wcześniejszą z dat, tę zapisaną w polu Hiredate lub 1 stycznia 1985. Funkcja Least wybierze wcześniejszą lub mniejszą wartość z podanych możliwości, podczas gdy Greatest wybierze największą. SELECT ENAME, LEAST(HIREDATE, TO_DATE('1-JAN-85')) FROM EMP ENAME LEAST(HIREDATE) ---------- -------------- JP 01-JAN-85 ALLEN 20-FEB-81 WARD 22-FEB-81 JONES 02-APR-81 MARTIN 28-SEP-81 BLAKE 01-MAY-81 CLARK 09-JUN-91 SCOTT 01-JAN-85 KING 17-NOV-81 TURNER 08-SEP-81 ADAMS 01-JAN-85 JAMES 03-DEC-81 FORD 03-DEC-81 MILLER 23-JAN-82

307 Rozdział 17. Interfejs Access a 2000 do Oracle a Obliczenia na datach Arytmetyka Sysdate Add_Months Nie ma prawdopodobnie typu danych, który sprawia więcej kłopotu niż daty. Poniżej opiszemy kilka funkcji, które operują na datach. Date jest typem danych zarówno w Oracle'u jak i w Accessie. Tak jak w Accessie daty zapisują więcej informacji niż to jest widoczne. W Oracle'u kolumna typu Date przechowuje rok, miesiąc, dzień, godzinę, minutę i sekundę. Oznacza to, że możesz przeprowadzać obliczenia na datach. Jednak w odróżnieniu od liczb, gdy dodasz liczbę do daty, otrzymujesz nową datę. Gdy odejmujesz jedną datę od drugiej, otrzymujesz liczbę oznaczającą czas pomiędzy tymi dwiema datami. W zależności od formatowania czas ten może wyglądać dowolnie, od lat po sekundy. Jest również możliwe, że liczba ta nie jest liczbą całkowitą identycznie jak w Accessie. Funkcja Sysdate() sięga do systemu operacyjnego i zwraca bieżącą datę i czas. Select SYSDATE FROM sys.dual Wyrażenie to zwróci datę systemową, używając systemowej tabeli testowej. Jeżeli pierwsza ocena pracownika powinna być po 6 miesiącach pracy, możesz użyć funkcji Add_Months, aby zaplanować ocenę. Add_Months posiada dwa parametry: Date wymagana. Data lub odwołanie do prawidłowej daty. Count wymagana. Ilość miesięcy, jaką należy dodać do Date. Poniższe wyrażenie SQL przedstawia datę pierwszej oceny pracownika. SELECT ename, hiredate, add_months(hiredate, 6) FROM emp SELECT ENAME, LEAST(HIREDATE, TO_DATE('1-JAN-85')) FROM EMP ENAME HIREDATE ADD_MONTH ---------- --------- --------- JP 27-JUL-97 27-JAN-98 ALLEN 20-FEB-81 20-AUG-81 WARD 22-FEB-81 22-AUG-81 JONES 02-APR-81 02-OCT-81 MARTIN 28-SEP-81 28-MAR-82 BLAKE 01-MAY-81 01-NOV-81 CLARK 09-JUN-81 09-DEC-81 SCOTT 19-APR-87 19-OCT-87 KING 17-NOV-81 17-MAY-82 TURNER 08-SEP-81 08-MAR-82 ADAMS 23-MAY-87 23-NOV-87 JAMES 03-DEC-81 03-JUN-82 FORD 03-DEC-81 03-JUN-82 MILLER 23-JAN-82 23-JUL-82 Często, gdy planujemy zdarzenia, potrzebujemy określonego czasu realizacji zdarzenia, aby zdążyć wykonać zakładane czynności. Można uzyskać datę rozpoczęcia realizacji poprzez wstawienie liczby ujemnej do drugiego argumentu funkcji Add_Months(). Months_Between Aby policzyć odstęp czasu pomiędzy dwiema datami, możesz odjąć jedną od drugiej. Miesiące jednak mają różną ilość dni i aby podać ilość miesięcy pomiędzy datami, musiałbyś wykonać sporo obliczeń. Funkcja Months_Between() zwraca różnicę w miesiącach pomiędzy datami, biorąc pod uwagę, które miesiące leżą pomiędzy nimi. Poniższe wyrażenie zamienia miesiące na lata poprzez podzielenie ich przez 12. Użyjemy również zaokrąglenia, aby otrzymać czytelny wynik. SELECT ename, hiredate, ROUND(MONTHS_BETWEEN(SYSDATE, hiredate)/12,2) "YEARS SERVICE" FROM emp ENAME HIREDATE YEARS SERVICE ---------- --------- ------------- JP 27-JUL-97 1.56 ALLEN 20-FEB-81 17.99 WARD 22-FEB-81 17.99 JONES 02-APR-81 17.88

Część V Access i architektura klient-serwer 308 Next_Day() To_Date() MARTIN 28-SEP-81 17.39 BLAKE 01-MAY-81 17.8 CLARK 09-JUN-81 17.69 SCOTT 19-APR-87 11.83 KING 17-NOV-81 17.25 TURNER 08-SEP-81 17.44 ADAMS 23-MAY-87 11.74 JAMES 03-DEC-81 17.21 FORD 03-DEC-81 17.21 MILLER 23-JAN-82 17.07 Jeżeli jakieś zdarzenie ma miejsce danego dnia tygodnia przed lub po podanej dacie (jak większość kalendarzowych świąt, niektóre święta religijne i dni wypłaty), można policzyć daty, kiedy będzie ono wypadnie. Funkcja Next_Day() może pomóc w takich obliczeniach. Next_Day() posiada dwa parametry: Date data lub odwołanie do prawidłowej daty Day angielska nazwa dnia tygodnia ('Sunday', 'Monday', itd.) Poniższe wyrażenie przedstawia pierwsze dni wypłaty pracowników, zakładając, że dostają pieniądze w każdy piątek. SELECT ename, hiredate, next_day(hiredate, 'Friday') "PAYDAY!" FROM emp ENAME HIREDATE PAYDAY! ---------- --------- --------- JP 27-JUL-97 01-AUG-97 ALLEN 20-FEB-81 27-FEB-81 WARD 22-FEB-81 27-FEB-81 JONES 02-APR-81 03-APR-81 MARTIN 28-SEP-81 02-OCT-81 BLAKE 01-MAY-81 08-MAY-81 CLARK 09-JUN-81 12-JUN-81 SCOTT 19-APR-87 24-APR-87 KING 17-NOV-81 20-NOV-81 TURNER 08-SEP-81 11-SEP-81 ADAMS 23-MAY-87 29-MAY-87 JAMES 03-DEC-81 04-DEC-81 FORD 03-DEC-81 04-DEC-81 MILLER 23-JAN-82 29-JAN-82 Funkcja To_Date() przeznaczona jest do zamiany daty zapisanej w postaci ciągu na wewnętrzny format daty rozpoznawany przez Oracle. Często będziesz jej używał w wyrażeniach Insert i Update. Bez niej nie byłbyś często w stanie przeprowadzić obliczeń na datach. To_Date posiada dwa parametry: Problem roku 2000 String wymagany. Ciąg reprezentujący datę (np.: 'July 27, 1997'). Domyślnym formatem daty jest DD- MON-YYYY. Format nieobowiązkowy. SELECT TO_DATE('27-jul-97', 'dd-mon-yyyy') "Data sformatowana" FROM sys.dual Data sformatowana ----------- 27-JUL-1997 Oracle nie przetwarza dat w sposób, w jaki robi to Access. Poniższe dwa wyrażenia SQL przedstawiają jak Oracle przypisuje daty do bieżącego stulecia (stulecia daty uzyskanej przez funkcję Sysdate()), gdy nie określimy sposobu konwersji. SELECT MONTHS_BETWEEN('27-JUL-2001', '27-JUL-1997') FROM SYS.DUAL MONTHS_BETWEEN('27-JUL-2001', '27-JUL-1997') -------------------------------------------- 48 SELECT MONTHS_BETWEEN('27-JUL-01', '27-JUL-97') FROM SYS.DUAL MONTHS_BETWEEN('27-JUL-01', '27-JUL-97') ---------------------------------------- -1152

309 Rozdział 17. Interfejs Access a 2000 do Oracle a Podczas tworzenia aplikacji musisz brać to pod uwagę. Pracując z datami, można użyć maski RR, aby konwertować zapisany dwucyfrowo rok na postać czterocyfrową według następujących zasad: jeżeli rok zawiera się w przedziale 0 49, zostanie przypisany do XXI wieku, natomiast pomiędzy 50 a 99 do wieku XX. SELECT TO_CHAR(TO_DATE('000727', 'RRMMDD'), 'DD-MON-YYYY') RRMMDD, TO_CHAR(TO_DATE('000727', 'YYMMDD'), 'DD-MON-YYYY') YYMMDD FROM SYS.DUAL RRMMDD YYMMDD ----------- ----------- 27-JUL-2000 27-JUL-1900 Poznajemy widoki i procedury przechowywane Przesyłanie wyrażeń SQL do wykonania przez Oracle jest świetnym sposobem na zwiększenie wydajności i zmniejszenie ruchu w sieci, lecz przechowywanie wyrażeń SQL w aplikacji nie jest najlepszym możliwym rozwiązaniem. Aby uruchomić całą siłę Oracle'a, skorzystać z pracy wykonanej w bazie danych, zmniejszyć koszty dodatkowych prac, zabezpieczyć swoją pracę i utrzymywać spójność danych, powinieneś użyć widoków i procedur przechowywanych. Widok w Oracle'u jest to po prostu zapytanie zapisane na serwerze. Tak jak kwerenda Select zapisana w Accessie, jest on skompilowany i posiada plan wykonania. Oznacza to, że będzie działać szybciej niż pytanie przesłane do wykonania przez SPT. Jest wiele zalet stosowania widoków. Można je wywoływać poprzez nazwę, która jest o wiele krótsza niż średnie wyrażenie SQL, przez co zmniejsza się obciążenie sieci. Ponieważ widok zapisany jest w bazie danych, posiada on dodatkowy poziom bezpie- czeństwa, co jest ważne w aplikacjach, które są słabo chronione. Ponieważ Twoja aplikacja prawdopodobnie nie jest jedyną, która korzysta z bazy danych, możesz skorzystać z gotowych widoków, co oszczędza czas i zapewnia spójność danych w różnych aplikacjach. Widoki można tworzyć za pomocą Accessa lub korzystając z narzędzi Oracle'a. Aby utworzyć widok lub przeprowadzić inną zmianę struktury bazy danych, użytkownik, który pracuje musi mieć nadane prawo Resource. Sprawdź, czy posiadasz wystarczające uprawnienia, lub zapytaj o to administratora bazy danych. W tym rozdziale zajmujemy się dostępem do Oracle'a z Accessa, więc wszystko, co opiszę, można wykonać za pomocą Accessa. Jeżeli jednak chciałbyś użyć SQL Plus lub innego narzędzia Oracle'a, sprawdź w dokumentacji jak ich używać. Tworzenie widoków Widok jest po prostu wyrażeniem SQL, które zwraca rekordy. Ponieważ widok jest częścią struktury bazy danych, może być tworzony, zmieniany, używany lub usuwany za pomocą poleceń SQL. Spójrzmy na proste wyrażenie SQL zapisane zgodnie ze składnią Oracle'a. Select * from emp where sal>3000 Możesz utworzyć je w Accessie i uruchomić jako kwerendę przekazującą lub możesz utworzyć widok w Oracle'u i wywołać ten widok. Aby utworzyć widok z Accessa, utwórz kwerendę przekazującą, zawierającą wyrażenie definicji danych (DDL). Wyrażenie takie rozpoczyna się słowami kluczowymi Create, Alter, Drop itd. Aby utworzyć widok, powinieneś użyć następującej składni: Create [or Replace] View [Nazwa widoku] AS [wyrażenie SQL zwracające rekordy] Aby stworzyć widok z poprzedniego wyrażenia SQL, powinieneś użyć poniższego wyrażenia DDL uruchomionego przy użyciu SPT:

Część V Access i architektura klient-serwer 310 Create or Replace View MyView As Select * from emp where sal>3000 Klauzula Or Replace powoduje, że nie zostanie wyświetlony błąd, gdy widok MyView już istnieje. Prawdopodobnie nie będziesz chciał zawsze dołączać klauzuli Or Replace, ponieważ bardzo łatwo wtedy omyłkowo zmienić definicję już istniejącego widoku. Wykonanie tej kwerendy utworzy widok, który zwraca wszystkie kolumny z tabeli emp, których wartość pola sal jest większa od 3000. Aby sprawdzić, czy widok został prawidłowo utworzony, możesz podłączyć ją do Accessa, jak gdyby była to zwykła tabela. Możesz również użyć go w dowolnym wyrażeniu SQL w kwerendzie przekazującej. lub Select * from MyView Select MyView.ename, Dept.deptno from MyView, Dept Where MyWiew.deptno=Dept.deptno Połączenie z Oracle'em poprzez ADO Tworzenie kwerend SPT jest świetną metodą komunikacji z Oracle'em, ponieważ przerzucają ciężar pracy na serwer zamiast na Jet, który nie jest uruchamiany. Możesz skorzystać z wszystkich zalet kwerend SPT, łącząc się z Oracle'em poprzez ADO. Podejście to pozwala efektywnie kontrolować poprawność danych, dynamicznie tworzyć wyrażenia SQL i wykonywać procedury przechowywane. Utworzenie połączenia z Oracle'em pociągało zwykle za sobą wiele skomplikowanych wywołań API z ODBC lub RDO, który jest podobnym do DAO interfejsem ODBC. Teraz mamy ADO i OLEDB, co zapewnia szybki, jednolity i elastyczny interfejs do różnych źródeł danych, włączając w to Oracle. Szczegółowy opis ADO i OLEDB znajduje się w rozdziale 6. Wprowadzenie do obiektów danych ActiveX i oraz w rozdziale 7. Zaawansowane ADO. W tej części rozdziału prześledzimy sposoby użycia ADO i OLEDB, aby połączyć się z bazą danych Oracle i wykonać wyrażenia SQL. Gdy używamy kwerend SPT, Oracle analizuje wyrażenia SQL i tworzy wynik. Oracle nie ma planu wykonania takiego zapytania, więc czas jego wykonania może nie być optymalny. Ponadto, gdy kilka aplikacji używa takiego samego zapytania lub procedury, musisz je zaprojektować i wstawić do wielu aplikacji. Lepszym podejściem jest utworzenie widoku lub procedury przechowywanej na serwerze. Może być on dzielony pomiędzy wiele aplikacji, zapewniając za każdym razem ten sam wynik. Ponieważ zarówno zapytanie tworzące widok, jak i procedura ma utworzony plan wykonania, więc będzie wykonana z maksymalną możliwą wydajnością. Omawialiśmy już, w jaki sposób utworzyć widok i procedurę przechowywaną przez użycie kwerend SPT. Wyrażenie SQL jest takie samo, ale użycie kodu ADO do zestawienia połączenia i utworzenia widoku lub procedury przechowywanej jest nieco inne. Przykłady w tym rozdziale są napisane w oparciu o dostawcę Oracle Native OLEDB z firmy Microsoft. Dostawca ten łączy z Oracle Call Interface (OCI), jednak w chwili obecnej nie wszystko, co da się zrobić za pomocą OCI, można wykonać, używając dostawcy OLEDB. Większość potrzebnych rzeczy da się wykonać, wykorzystując istniejący zestaw funkcji. Program z wydruku 17.1 tworzy widok w Oracle'u, a później otwiera go i wyświetla jego zawartość w oknie debuggera. Wydruk 17.1. Tworzenie widoku w Oracle'u z Accessa Function Create0racleView() As Boolean Dim conn As New ADODB.Connection Dim cmd As New ADODB.Command On Error GoTo Create0racleView Err With conn.provider = "MSDAORA".ConnectionString = "Data Source=empexample; User ID=Scott;password=Tiger".Open End With cmd.activeconnection = conn cmd.commandtype = adcmdtext

311 Rozdział 17. Interfejs Access a 2000 do Oracle a ' Wyrażenie SQL Create or Replace oszczędza nam obsługi błędów cmd.commandtext = "Create or Replace View MyView As _ Select * firom emp where SAL>2000" cmd.execute Create0racleView_Exit: conn.close Set conn = Nothing Set cmd = Nothing Exit Function Create0racleView Err: ' Błąd Create0racleView = False ' Sprawdź, który błąd wystąpił przeszukując tablicę błędów With conn For i = 0 To.Errors.Count - 1 errdesc = errdesc &.Errors(i).Description & Chr(13) Next End With ' Powiadom użytkownika MsgBox "Wystąpił błąd: " & errdesc Resume Create0racleView Exit End Function Parametry W Accessie programista może tworzyć kwerendy sparametryzowane, mają one jednak tylko podstawowy plan wykonania i wykonują się w oparciu o ten plan z różnymi wartościami parametrów. Niestety Oracle nie udostępnia parametrów widoku poprzez dostawcę OLEDB. Alternatywą jest zmiana istniejącego widoku, tak jak pokazaliśmy powyżej. Można również użyć obiektu polecenia z OLEDB, aby utworzyć i dostarczyć parametry do wyrażenia SQL. Program na wydruku 17.2 przedstawia, w jaki sposób można to wykonać. Wydruk 17.2. Użycie parametrów Oracle'a z VBA Accessa Function OracleParams(SalAmnt As Long) As Boolean Dim conn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim rsfield as New Field Dim cmd As New ADODB.Command ' Tworzenie połączenia With conn.provider = "MSDAORA".ConnectionString = "Data Source=empexample; User ID=Scott;password=Tiger".Open End With ' Użyjemy kursorów po stronie serwera With rs.cursorlocation = aduseserver End With ' Tworzenie obiektu polecenia With cmd cmd.activeconnection = conn ' Ustawienie CommandType, aby akceptował wyrażenia SQL cmd.commandtype = adcmdtext ' Ustawienie tekstu polecenia cmd.commandtext = "Select * from emp where sal >?" ' Tworzenie parametru i dołączenie go do zbioru ' parametrów polecenia cmd.parameters.append cmd.createparameter("sal", adnumeric, adparaminput) ' Przypisanie wartości SalAmnt do pierwszego parametru cmd(0) = SalAmnt End With ' Wykonaj polecenie i przypisz wynik do obiektu ADO Recordset Set rs = cmd.execute If conn.errors.count = 0 Then OraclParams = True End If rs.movefirst While Not rs.eof strfield = "" For Each rsfield In rs.fields strfield = strfield & " " & rsfield Next Debug.Print strfield & Chr(9) rs.movenext Wend End Function

Część V Access i architektura klient-serwer 312 Tworzenie procedur przechowywanych Procedura przechowywana w Oracle'u jest podobna do modułu w Accessie. Wykonuje zbiór poleceń na serwerze. Głównymi zaletami procedur przechowywanych są ich szybkość, niezawodność i bezpieczeństwo. Mogą one być użyte do wymuszania reguł biznesowych, kontroli poprawności i zapewnienia transakcyjności. Najważniejszą wadą procedur jest sposób ich tworzenia i uruchamiania. Oracle nie dostarcza środowiska programowania podobnego do środowiska Accessa, przez to tworzenie i edycja procedur przechowywanych jest trudna. Oracle 8 dostarcza program zarządzania strukturą bazy, który umożliwia tworzenie i kontrolę poprawności procedur, jednak wciąż nie jest to idealne rozwiązanie. Dodatkowo z racji tego, że procedury są zależne od serwera bazy danych, gdy zmieniasz serwer, musisz również zmienić procedury przechowywane. Architektura wielowarstwowa została tak zaprojektowana, aby ograniczyć tę niedogodność. Nie ma żadnego powodu, aby umieszczać całą skomplikowaną logikę aplikacji na serwerze (tak samo jak nie ma powodu, aby umieszczać ją na kliencie), dzięki temu procedury przechowywane są dużo prostsze od innych obiektów zapewniających logikę biznesową i inne operacje. Poniżej utworzymy i uruchomimy prostą procedurę przechowywaną. Aby tworzyć procedury w swojej przestrzeni tabel bazy danych, trzeba posiadać prawo systemowe Create Procedure, które jest częścią roli Resource. Aby utworzyć procedurę w innej przestrzeni tabel, musisz posiadać prawo Create Any Procedure. Porozmawiaj z administratorem bazy, jeżeli nie jesteś pewien, jakie posiadasz uprawnienia. Procedura dzieli się na następujące części: Deklaracja parametrów. Rozpoczęcie przetwarzania. Zatwierdzenie zmian. Obsługa wyjątków. Odwołanie zmian. Obsługa błędów. Procedura wstawiająca rekord do tabeli z dwoma polami przedstawiona jest na wydruku 17.3. Wydruk 17.3. Procedura Oracle'a dodająca nowy rekord (Ename CHAR, EJob CHAR) IS BEGIN INSERT INTO SCOTT.TESTTABLE VALUES(Ename, EJob); COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE; END; W tym przypadku procedura posiada dwa parametry, nazwisko i nazwę stanowiska. Access może utworzyć procedurę poprzez kwerendę SPT w następujący sposób: CREATE OR REPLACE PROCEDURE MyStoredProcedure (Ename CHAR, EJob CHAR) IS BEGIN INSERT INTO SCOTT.TESTTABLE VALUES(Ename, EJob); COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE; END; Po utworzeniu procedury może być ona wywoływana poprzez kwerendę SPT lub VBA.

313 Rozdział 17. Interfejs Access a 2000 do Oracle a Uruchamianie procedury Wywołanie procedury z kwerendy SPT jest nieco inne niż wywołanie widoku: {call MyStoredProcedure } Nawiasy klamrowe udają składnię, jakiej spodziewa się Oracle, używając Oracle call interface, używanego przez dostawcę OLEDB. Wykonywanie procedury z VBA poprzez dostawcę OLEDB dla Oracle'a wygląda nieco inaczej. Funkcja przedstawiona na wydruku 17.4 korzysta z tego, że procedury ujawniają swoje parametry w sposób, który może być użyty w VBA. Podając nazwę procedury przechowywanej, nazwę tabeli, do której chcesz wstawić rekord i wypełniając wymagane argumenty w tablicy paramarray uruchamianej funkcji, możesz uruchomić większość procedur przechowywanych za pomocą funkcji przedstawionej na wydruku 17.4. Wydruk 17.4. Wykonanie procedury przechowywanej z parametrami za pomocą VBA w Accessie Function RunOracleStoredProcedures(ProcName As String, _ DestTable as String, ParamArray ParamArgs() As Variant) As Boolean Dim conn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim i As Integer Dim cmd As New ADODB.Command Dim rsfield As Field Dim strfield As String With conn.provider = "MSDAORA".ConnectionString = "Data Source=empexample;_ User ID=Scott;password=Tiger".Open End With cmd.activeconnection = Conn cmd.commandtype = adcmdstoredproc cmd.commandtext = ProcName For i = 0 To UBound(ParamArgs()) With cmd.parameters(i).type = adchar.direction = adparaminput.value = ParamArgs(i) End With Next cmd.execute ' A teraz wyświetlamy wynik w oknie uruchamiania ' Nie będziesz potrzebował tego fragmentu kodu ' w swoich aplikacjach rs.open "Select * from " & desttable, conn,_ adopenforwardonly, adlockreadonly rs.movefirst While Not rs.eof strfield = "" For Each rsfield In rs.fields strfield = strfield & " " & rsfield Next Debug.Print strfield & Chr(9) rs.movenext Wend Set rs = Nothing conn.close RunOracleStoredProcedures = True End Function Wykonywanie wielu prostych procedur przechowywanych umożliwia tworzenie złożonej logiki w znanym środowisku VBA, korzystając z jego zaawansowanych możliwości uruchamiania kodu i obsługi błędów. Tworzenie niezwiązanego interfejsu do Oracle'a Mając na uwadze ograniczenia wydajności i duże obciążenie sieci, gdy używamy tabel połączonych, powinniśmy rozważyć użycie niezwiązanego interfejsu użytkownika wszędzie tam, gdzie jest to możliwe. Utworzenie niezwiązanego interfejsu pomaga zastosować w Twojej aplikacji architekturę wielowarstwową, co zwiększa jej skalowalność i ułatwia jej konserwację. Umożliwi także łatwe łączenie różnych narzędzi programowania. Możesz użyć ADO, ADOX, DAO, RDO i inne narzędzia tam, gdzie uważasz, że przyniosą korzyści. Niezwiązany interfejs ułatwia migrację do innego środowiska,

Część V Access i architektura klient-serwer 314 jak na przykład Visual Basic. Przez to, że jesteś pewny, że przetwarzanie odbywa się na serwerze, możesz również uzyskać lepszą wydajność. W przedstawionym tu ćwiczeniu utworzymy prosty niezwiązany interfejs dla Oracle'a, który wygląda i zachowuje się identycznie jak formularz związany. Aby pokazać elastyczność ADO, użyjemy wyrażeń SQL oraz metod obiektu Recordset. Formularz będzie wyświetlał rekordy tabeli EMP. Użytkownik będzie mógł wstawiać i usuwać rekordy z bazy danych Oracle. Można będzie zmieniać rekordy w tabeli bez konieczności każdorazowego zapisywania zmienionego rekordu. Tworzenie niezwiązanego interfejsu Rysunek 17.3. Formularz z danymi w trybie projektowania Na początek utwórz formularz taki, jak na rysunku 17.3. Dla uproszczenia, nazwy obiektów ekranowych odpowiadają nazwom pól w tabeli EMP: Empno, Ename, Job, Mgr, Hiredate, Sal, Comm, Deptno. Przyciski nawigacyjne i manipulacyjne będą nazywały się następująco: BtnGotoFirst, BtnGotoPrevious, BtnGotoNext, BtnGotoLast, BtnEdit, BtnNew, BtnDelete, BtnSave, BtnClose. Tworzenie zmiennych globalnych Podstawowe operacje można zrobić na kilka sposobów. Dla uproszczenia przyjmijmy, że obiekty Connection i Recordset oraz zmienna, która informuje o zmianie danych, będą przechowywane przez trzy zmienne globalne przechowywane w głównym module:

315 Rozdział 17. Interfejs Access a 2000 do Oracle a Global conn As ADODB.Connection Global rs As ADODB.Recordset Global EditRec As Boolean Ładowanie danych i inicjalizacja formularza Program przedstawiony na wydruku 17.5 wykonany zostanie jako obsługa komunikatu OnOpen. Procedura ta załaduje dane i zainicjuje aplikację. Wydruk 17.5. Utworzenie i otwarcie połączenia z Oracle'em oraz wypełnienie formularza Private Sub Form Open(Cancel As Integer) Set conn = New ADODB.Connection Set rs = New ADODB.Recordset With conn.provider = "MSDAORA".ConnectionString = "Data Svurce-ernpexample;_ User ID=Scott;password=Tiger".Open End With rs.cursorlocation = aduseclient rs.open "Select * from emp", conn, adopenstatic,_ adlockoptimistic, adasyncfetch FillForm EditRec = True End Sub Oracle nie zwraca obiektów typu Recordset, ale dostawca OLEDB przechwytuje wynik wyrażenia SQL i zwraca go do programu jako Recordset. Dostawca OLEDB przykrywa wywołania Oracle Call Interface tak, że dla aplikacji nie ma różnicy pomiędzy Oracle'em a innymi źródłami danych. Używając globalnej zmiennej Recordset, można szybko i łatwo wypełnić formularz danymi pochodzącymi z pierwszego rekordu. Następnie procedura ustawia zmienną EditRec na true, co wskazuje, że dane na formularzu są gotowe do edycji. Zdarzenie OnOpen wywołuje funkcję FillForm, która zamieszczona jest na wydruku 17.6. Wydruk 17.6. Wypełnianie formularza danymi Function FillForm() As Boolean On Error GoTo FillForm Err [Empno] = rs(0) [ENAME] = rs(1) [Job] = rs(2) [MGR] = rs(3) [HIREDATE] = rs(4) [SAL] = rs(5) [COMM] = rs(6) [DEPTNO] = rs(7) FillForm = True FillForm_Exit: Exit Function FillForm_Err: FillForm = False Exit Function End Function Programowanie przycisków sterujących Aby przeglądać cały wynik zapytania, należy oprogramować przyciski sterujące, tak jak jest to pokazane na wydrukach od 17.7 do 17.10. Wydruk 17.7. Przejście do pierwszego rekordu Private Sub btngotofirst_click() On Error Resume Next rs.movefirst If Not rs.bof Then FillForm End If CurrentContext Me End Sub

Część V Access i architektura klient-serwer 316 Wydruk 17.8. Przejście do poprzedniego rekordu Private Sub btngotoprevious_click() On Error Resume Next rs.moveprevious If Not rs.bof Then FillForm End If CurrentContext Me End Sub Wydruk 17.9. Przejście do następnego rekordu Private Sub btngotonext_click() On Error Resume Next rs.movenext If Not rs.bof Then FillForm End If CurrentContext Me End Sub Wydruk 17.10. Przejście do ostatniego rekordu Private Sub btngotolast_click() On Error Resume Next rs.movelast If Not rs.bof Then FillForm End If On Error GoTo 0 CurrentContext Me End Sub Bieżący stan przycisków nawigacyjnych zależy od pozycji w zestawie rekordów wyniku. Funkcja CurrentContext, która pobiera jako argument obiekt formularza, włącza oraz wyłącza przyciski nawigacyjne (wydruk 17.11). Wydruk 17.11. Włączanie i wyłączanie przycisków nawigacyjnych Sub CurrentContext(frm As Form) Dim bfirstrec As Boolean Dim blastrec As Boolean bfirstrec = (rs.absoluteposition = 1) blastrec = (rs.absoluteposition = rs.recordcount) With frm If Not bfirstrec And Not blastrec Then!btnGotoFirst.Enabled = True!btnGotoPrevious.Enabled = True!btnGotoLast.Enabled = True!btnGotoNext.Enabled = True GoTo CurrentContext_Exit End If If bfirstrec And blastrec Then!btnEdit.SetFocus!btnGotoFirst.Enabled = False!btnGotoPrevious.Enabled = False!btnGotoLast.Enabled = False!btnGotoNext.Enabled = False GoTo CurrentContext_Exit End If If bfirstrec Then!btnGotoLast.Enabled = bfirstrec!btngotonext.enabled = bfirstrec!btngotolast.setfocus!btngotofirst.enabled = Not bfirstrec!btngotoprevious.enabled = Not bfirstrec GoTo CurrentContext_Exit End If If blastrec Then!btnGotoFirst.Enabled = blastrec!btngotoprevious.enabled = blastrec!btngotofirst.setfocus

317 Rozdział 17. Interfejs Access a 2000 do Oracle a!btngotolast.enabled = Not blastrec!btngotonext.enabled = Not blastrec GoTo CurrentContext_Exit End If End With End Sub Zmiana danych Oracle'a przy użyciu formularza Do tej pory możesz tylko oglądać dane, ale zmiany, jakie wprowadziłeś, nie zostaną zapisane w bazie. Funkcja z wydruku 17.12 wywołuje metodę Update obiektu OLEDB Recordset, aby wysłać zmiany do Oracle'a zaraz po tym, jak zmieniłeś dane. Daje to możliwości takie same jak możliwości formularza związanego. Funkcja pokazana na wydruku 17.12 musi być wywołana jako odpowiedź na zdarzenie AfterUpdate dla każdego pola tekstowego. Wydruk 17.12. Funkcja UpdateField Function UpdateField(FieldName As Variant, NewValue As Variant)_ As Boolean If EditRec = False Or IsEmpty(EditRec) Then Exit Function Dim rsorigsource As String Dim errdesc As String Dim i As Integer On Error GoTo UpdateField Err ' Zachowaj początkowe źródło recordset-u na wypadek błędu rsorigsource = rs.source ' Próba zmiany pola przy użyciu metody update obiektu Recordset rs.update FieldName, NewValue ' Udało się UpdateField = True UpdateField_Exit: Exit Function UpdateField_Err: ' Błąd UpdateField = False ' Sprawdź, jaki wystąpił błąd, przeszukując tablicę błędów With conn For i = 0 To.Errors.Count - 1 errdesc = errdesc &.Errors(i).Description & Chr(13) Next End With ' Informacja dla użytkownika MsgBox "Wystąpił błąd: " & errdesc ' Musisz odwołać metodę Update metodą CancelUpdate ' gdyż nie będziesz mógł wykonać żadnej operacji na wyniku rs.cancelupdate ' Zamknięcie istniejącego wyniku rs.close ' Otwórz Recordset z zachowanym źródłem, przywracając ' mu stan początkowy rs.open rsorigsource, conn, adopenstatic, adlockoptimistic, _ adasyncfetch ' Wywołaj FillForm Forms![forml].FillForm Resume UpdateField_Exit End Function Funkcja UpdateField może być wywoływana przez każde zdarzenie AfterUpdate, gdy zaznaczymy wszystkie pola tekstowe na formatce i wstawimy wyrażenie pokazane na wydruku 17.13. Alternatywą do zapisywania zmian natychmiast może być buforowanie zmian i zapisywanie ich po przejściu do innego rekordu. Możesz także użyć wywołania przez ADO procedury przechowywanej i przekazać do niej nowe wartości. Wydruk 17.13. Wyrażenie zapisujące zmiany po edycji zawartości pola =UpdateField(screen.activecontrol.[Name],screen.activecontrol)

Część V Access i architektura klient-serwer 318 Teraz, gdy przechodzisz między rekordami i zmieniasz dane pracowników, zmiany zapisane będą w bazie po przejściu do innego rekordu. Wstawienie danych do Oracle'a przy użyciu formularza Aby dodać nowy rekord, powinieneś wyczyścić wszystkie pola na formularzu i ustawić zmienną EditRec na false. Kod programu z wydruku 17.14 powinien być wprowadzony jako obsługa zdarzenia OnClick przycisku btnnew. Wydruk 17.14. Przygotowanie formularza do wpisania nowego rekordu Private Sub btnnew Click() ClearForm EditRec = False End Sub Należy jeszcze napisać procedurę czyszczącą formularz. Dla naszych celów, może ona być zapisana w standardowym module poza formularzem. Funkcja ta jest niezwykle prosta (wydruk 17.15). Wydruk 17.15. Czyszczenie formularza Sub ClearForm() Me![Empno] = "" Me![ENAME] = "" Me![Job] = "" Me!(MGR] = "" Me![HIREDATE] = "" Me![SAL] = "" Me![COMM] = "" Me![DEPTNO] = "" End Sub Zapisywanie danych do Oracle'a przy użyciu formularza Gdy trzeba zapisać rekord, możesz wywołać poniższą procedurę za pomocą zdarzenia OnClick przycisku btnsave. Sprawdzając stan zmiennej EditRec, wiemy, czy wprowadzasz nowy rekord i tworzymy odpowiednie wyrażenie SQL. Zostanie ono wykonane poprzez obiekt Command. Technika ta pokazana jest na wydruku 17.16, jest standardowa dla Oracle'a. Wydruk 17.16. Zapis do Oracle'a poprzez SQL i ADO Private Sub btnsave Click() Dim cmd As New ADODB.Command Dim strcmdtxt as string ' Jeżeli wstawiamy nowy rekord If EditRec = False Then ' Po upewnieniu się, że obiekt Command jest prawidłowo ustawiony ' utworzymy i wykonamy wyrażenie SQL Insert With cmd.activeconnection = conn.commandtype = adomdtext with Me stromdtxt = stromdtxt & "insert into emp values (" strcmdtxt = strcmdtxt & "'![Empno] '," stromdtxt = strcmdtxt & "'![ENAME] '," strcmdtxt = strcmdtxt & "'![Job] '," strcmdtxt = strcmdtxt & "'![MGR] '," strcmdtxt = strcmdtxt & "' to date('" &![HIREDATE] & "','MM/DD/YY') '," strcmdtxt = strcmdtxt & "'![SAL] '," strcmdtxt = strcmdtxt & "'![COMM] '," end with.execute End With End If ' Zamknij, ustaw i otwórz jeszcze raz Recordset With rs.close.cursorlocation = aduseclient.open "Select * from emp", conn, adopenstatic, adlockoptimistic, adasyncfetch End With ' Wypełnij formularz FillForm

319 Rozdział 17. Interfejs Access a 2000 do Oracle a ' Zmień tryb aplikacji na edycję danych EditRec = True End Sub Usuwanie danych przy użyciu formularza To samo podejście zastosowane jest przy usuwaniu danych. Procedura na wydruku 17.17 usuwa bieżący rekord z Oracle'a, gdy wykonamy ją jako obsługę zdarzenia OnClick przycisku btndelete. Wydruk 17.17. Usunięcie bieżącego rekordu Private Sub btndelete Click() Dim cmd As New ADODB.Command ' Jeżeli zmieniamy rekord If EditRec = True Then ' Po upewnieniu się, że obiekt command jest prawidłowo ustawiony ' utworzymy i wykonamy wyrażenie SQL Delete With cmd.activeconnection = conn.commandtype = adcmdtext.commandtext = "Delete from emp where empno= " & Me![Empno].Execute End With End If ' Zamknij, ustaw i otwórz jeszcze raz Recordset With rs.close.cursorlocation = aduseclient.open "Select * from emp", conn, adopenstatic, adlockoptimistic, adasyncfetch End With ' Wypełnij formularz FillForm End Sub Aby przyciski nawigacyjne odzwierciedlały zawartość formularza w czasie przeglądania dostępnych rekordów, przypisz kod zamieszczony na wydruku 17.18 do zdarzenia OnCurrent formularza. Wydruk 17.18. Wypełnienie pól formularza danymi i sprawdzenie bieżącego kontekstu Private Sub Form Current() On Error Resume Next Dim bfirstrec As Boolean Dim blastrec As Boolean If Not rs.bof Then With Me![Empno] = rs(0)![ename] = rs(1)![job] = rs(2)![mgr] = rs(3)![hiredate] = rs(4)![sal] = rs(5)![comm] = rs(6)![deptno] = rs(7) End With End If Current0ontext Me End Sub Zamykanie połączenia z Oracle'em Gdy zamykamy formularz, należy zakończyć połączenie z Oracle'em i ustawić obiekty Connection i Recordset na wartość nothing, ponieważ może zechcesz użyć tych obiektów w innych aplikacjach. Funkcja przedstawiona na wydruku 17.19 pomoże przeprowadzić prace porządkowe. Wydruk 17.19. Porządki podczas zamykania formatki Private Sub btnclose_click() On Error GoTo Err_btnClose_Click_Err DoCmd.Close Exit_btnClose_Click_Exit: conn.close Set conn = Nothing

Część V Access i architektura klient-serwer 320 Set rs = Nothing Exit Sub Err_btnClose_Click_Err: MsgBox err.description Resume Exit_btnClose_Click_Exit End Sub Poprzez wprowadzanie innych obiektów Recordset, trwałych obiektów Recordset oraz przez użycie uproszczeń dostawcy OLEDB dla Oracle Call Interface możesz utworzyć cały niezwiązany interfejs użytkownika do Oracle'a, korzystając z szybkości działania, skalowalności i odporności Oracle'a w Twojej aplikacji Accessa.