Bazy postrelacyjne i hybrydowe. ´Cwiczenia
Transkrypt
Bazy postrelacyjne i hybrydowe. ´Cwiczenia
Bazy postrelacyjne i hybrydowe. Ćwiczenia Bartosz Zieliński 14 stycznia 2012 Spis treści 1 Powtórzenie SQL 1.1 Nadanie uprawnień do tabel w schemacie HR . . . . . . . . . . . . . 1.2 Zadania z SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.1 Złaczenia EMPLOYEES/DEPARTMENTS . . . . . . . . . . , 1.2.2 Pracownicy i średnie płace . . . . . . . . . . . . . . . . . . . . 1.3 Zadania z DML i DDL . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.1 Tworzenie zmodyfikowanej cześciowej kopii tabeli EMPLOY, EES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Zadania z podstaw PL/SQL 2.1 Bloki i instrukcje warunkowe 2.1.1 Ocena średniej płacy . 2.2 Petle . . . . . . . . . . . . . . . , 2.2.1 Prosta iteracja . . . . . 2.2.2 Ciag , Fibonacciego . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Zadania z obiektów 3.1 Proste typy obiektowe i tabele obiektowe . . . . . . . . . . . . . . . 3.1.1 Typ Employee Type . . . . . . . . . . . . . . . . . . . . . . . . 3.1.2 Typ Department Type i referencje do obiektów wierszowych 3.2 Ewolucja typów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1 Dodatkowe kolumny w Employee Type . . . . . . . . . . . . 3.2.2 Dodawanie metod do typów . . . . . . . . . . . . . . . . . . . 3.3 Dziedziczenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Podtyp typu Employee Type . . . . . . . . . . . . . . . . . . . 2 . . . . . 4 4 5 5 6 9 . 9 . . . . . 10 10 10 11 11 11 . . . . . . . . 13 13 13 15 16 16 17 20 20 S PIS TRE ŚCI 4 Zadania z kolekcji 4.1 Funkcje i typy pomocnicze . . . . . . . . . . . . . . . . . . . 4.2 Zadania z tabel zagnieżdżonych jednopoziomowo . . . . . . 4.2.1 Tablica ciagów liczbowych . . . . . . . . . . . . . . . , 4.3 Tabele wielokrotnie zagnieżdżone . . . . . . . . . . . . . . . 4.3.1 Kraje, regiony, lokalizacje . . . . . . . . . . . . . . . 4.3.2 Ewolucja typów i tabele wielokrotnie zagnieżdżone 5 Zadania z XML Schema 5.1 Instalacja EditiX . . . . . . . . . . . . . . . . . . . . . 5.2 Tworzenie przykładowego schematu. . . . . . . . . . . 5.3 Przechowywanie XML w repozytorium XML DB . . . 5.4 Generowanie dokumentów XML z danych relacyjnych 5.5 XMLPath w Oraclu . . . . . . . . . . . . . . . . . . . . 5.6 XQuery – jezyk zapytań do dokumentów XML . . . . , 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 22 23 23 26 26 28 . . . . . . 31 31 31 32 34 38 40 Rozdział 1 Powtórzenie SQL 1.1 Nadanie uprawnień do tabel w schemacie HR Aby nadać uprawnienia użytkownikowi stud01 uprawnienia do wykonywania zapytań do tabel ze schematu HR (co bedzie potrzebne w dalszej pracy) należy na , koncie administracyjnym (np. SYS) wykonać nastepuj acy kod: , , declare x varchar2(500); begin for y in (select table_name from all_tables where owner=’HR’) loop x:=’grant select on HR."’||y.table_name ||’" to stud01’; execute immediate x; end loop; end; Zmodyfikować stosownie do potrzeb. 4 R OZDZIAŁ 1 P OWT ÓRZENIE SQL 1.2 Zadania z SELECT 1.2.1 Złaczenia EMPLOYEES/DEPARTMENTS , 1. Wypisać zawartość tabeli EMPLOYEES ze schematu HR. Rozwiazanie , select * from hr.employees; 2. Wypisać zawartość tabeli DEPARTMENTS ze schematu HR. Rozwiazanie , select * from hr.departments; 3. Wypisać zestawienie employee_id, first_name, last_name, department_name używajac ń , złacze , a) wewnetrznego (inner join), , b) lewego zewnetrznego (left outer join), , c) prawego zewnetrznego (right outer join), , d) pełnego zewnetrznego (full outer join) , tabel EMPLOYEES i DEPARTMENTS. Porównać wyniki. Rozwiazanie , -- a) select p.employee_id,p.first_name,p.last_name,q.department_name from hr.employees p inner join hr.departments q on p.department_id= q.department_id; -- b) select p.employee_id,p.first_name,p.last_name,q.department_name from hr.employees p left outer join hr.departments q on p.department_id= q.department_id; -- c) select p.employee_id,p.first_name,p.last_name,q.department_name from hr.employees p right outer join hr.departments q on p.department_id= q.department_id; 5 R OZDZIAŁ 1 P OWT ÓRZENIE SQL -- d) select p.employee_id,p.first_name,p.last_name,q.department_name from hr.employees p full outer join hr.departments q on p.department_id= q.department_id; 4. Wypisać zestawienie employee_id, first_name, last_name, department_name, "Imie i nazwisko szefa" tak aby w zestawieniu pojawili sie, wszyscy pracownicy. Rozwiazanie , select p.employee_id,p.first_name,p.last_name,q.department_name, r.first_name||’ ’|| r.last_name "Imie i nazwisko szefa" from (hr.employees p left outer join hr.departments q on p.department_id= q.department_id) left outer join hr.employees r on p.manager_id= r.employee_id; 1.2.2 Pracownicy i średnie płace 1. Wypisać średnia, płace, wszystkich pracowników zaokraglon a, do 2 miejsc po , przecinku. Rozwiazanie , select round(avg(salary),2) from hr.employees; 2. Wypisać dane pracowników których płaca jest wyższa od średniej. Rozwiazanie , select * from hr.employees p where p.salary > ( select avg(q.salary) from hr.employees q ); 3. Wypisać dane pracowników których płaca jest wyższa od średniej dla departamentu. Rozwiazanie , select * from hr.employees p where p.salary > ( select avg(q.salary) from hr.employees q 6 R OZDZIAŁ 1 P OWT ÓRZENIE SQL where q.department_id= p.department_id ); 4. Wypisać zestawienie first_name, last_name, "loser/winner" gdzie w kolumnie "loser/winner" powinna znaleźć sie, wartość ’loser’ gdy pracownik zarabia poniżej średniej dla departamentu i ’winner’ gdy zarabia powyżej. Skorzystać z wyrażenia CASE. Rozwiazanie , select p.first_name,p.last_name, case when p.salary > ( select avg(q.salary) from hr.employees q where q.department_id= p.department_id) then ’winner’ else ’loser’ end "loser/winner" from hr.employees p; 5. Wypisać zestawienie średnich i maksymalnych płac oraz ilości pracowników dla każdego department_id. Rozwiazanie , select count(p.employee_id) "N", avg(p.salary) "avg", max(p.salary) "max",p.department_id from hr.employees p group by p.department_id; 6. To samo co wyżej ale z nazwami departamentów. Uwaga: w zestawieniu powinien znaleźć sie, także wiersz podsumowujacy pracowników nie przypi, sanych do żadnego departamentu. Rozwiazanie , select e."N",e."max",e."avg",q.department_name from ( select count(p.employee_id) "N", avg(p.salary) "avg", max(p.salary) "max",p.department_id from hr.employees p group by p.department_id ) e left outer join hr.departments q on q.department_id=e.department_id; 7 R OZDZIAŁ 1 P OWT ÓRZENIE SQL 7. Dodać do zestawienia powyżej kolumne, z imieniem i nazwiskiem pracownika o najwyższej pensji. Rozwiazanie , select e."N",e."max",e."avg",q.department_name, t.first_name||’ ’|| t.last_name "Best paid" from (( select count(p.employee_id) "N", avg(p.salary) "avg", max(p.salary) "max",p.department_id from hr.employees p group by p.department_id ) e left outer join hr.departments q on q.department_id=e.department_id) inner join hr.employees t on t.salary=e."max" and coalesce(t.department_id,-1)=coalesce(e.department_id,-1); 8. Dodać do zestawiania z punktu powyżej kolumne, z ilościa, pracowników z pensja, powyżej średniej. Rozwiazanie , select e."N",e."above average",e."max",round(e."avg",2), q.department_name,t.first_name||’ ’ || t.last_name "Best paid" from (( select count(p.employee_id) "N", avg(p.salary) "avg", max(p.salary) "max",p.department_id, sum( case when p.salary > ( select avg(x.salary) from hr.employees x where p.department_id= x.department_id or (p.department_id is null and x.department_id is null)) then 1 else 0 end ) "above average" from hr.employees p group by p.department_id ) e left outer join hr.departments q on q.department_id=e.department_id) inner join hr.employees t on t.salary=e."max" and coalesce(t.department_id,-1) =coalesce(e.department_id,-1); 8 R OZDZIAŁ 1 P OWT ÓRZENIE SQL 1.3 Zadania z DML i DDL 1.3.1 Tworzenie zmodyfikowanej cześciowej kopii tabeli EMPLOYEES , 1. Stworzyć tabele, (we własnym schemacie) o nazwie EMPLOYEES z kolumnami employee_id, first_name, last_name, department_id tych samych typów co odpowiadajace kolumny w tabeli HR.EMPLOYEES. EMPLOYEE_ID po, winien być PRIMARY KEY. Rozwiazanie , CREATE TABLE "EMPLOYEES" ( "EMPLOYEE_ID" NUMBER(6,0) PRIMARY KEY, "FIRST_NAME" VARCHAR2(20 BYTE), "LAST_NAME" VARCHAR2(25 BYTE) NOT NULL, "DEPARTMENT_ID" NUMBER(4,0) ); 2. Skopiować dane do tabeli EMPLOYEES z tabeli HR.EMPLOYEES. Rozwiazanie , insert into employees(employee_id, first_name, last_name, department_id) select employee_id, first_name, last_name, department_id from hr.employees; 3. Dodać do tabeli EMPLOYEES kolumne, SALARY o tym samym typie co odpowiadajaca kolumna w tabeli HR.EMPLOYEES. , Rozwiazanie , alter table Bartek.employees add (salary NUMBER(8,2)); 4. Uzupełnić dane w nowoutworzonej kolumnie danymi z tabeli HR.EMPLOYEES. Rozwiazanie , update employees p set salary=( select q.salary from hr.employees q where q.employee_id= p.employee_id ); 9 Rozdział 2 Zadania z podstaw PL/SQL 2.1 Bloki i instrukcje warunkowe 2.1.1 Ocena średniej płacy Napisać blok anonimowy który wypisuje na dbms_output napis ’Niezla srednia’ lub ’Kiepska srednia’ zależnie od tego czy średnia płaca pracowników (w tabeli HR.EMPLOYEES) jest wieksza czy mniejsza od 5000 oraz poda sama, , średnia. , Rozwiazanie , declare x number; begin select avg(salary) into x from hr.employees; if x>5000 then dbms_output.put_line(’Niezla srednia’); else dbms_output.put_line(’Kiepska srednia’); end if; dbms_output.put_line(’srednia=’||to_char(x)); end; 10 R OZDZIAŁ 2 Z ADANIA Z PODSTAW PL/SQL 2.2 Petle , 2.2.1 Prosta iteracja 1. Napisać blok PL/SQL który wypisuje na dbms_output liczby od 0 do 10. Rozwiazanie , declare begin for i in 0..10 loop dbms_output.put_line(i); end loop; end; 2. Napisać blok PL/SQL który wypisuje na dbms_output imie, , nazwisko i płace, każdego z pracowników z tabeli HR.EMPLOYEES. Rozwiazanie , declare begin for x in ( select first_name,last_name,salary from hr.employees ) loop dbms_output.put_line(x.first_name||’ ’||x.last_name ||’ ’||to_char(x.salary)); end loop; end; 2.2.2 Ciag , Fibonacciego Napisać blok PL/SQL który wypisuje na dbms_output wszystkie liczby z ciagu , Fibonacciego aż do pierwszej wiekszej od 1000. Skorzystać z nieograniczonej ite, racji LOOP. Rozwiazanie , declare a integer:=0; b integer:=1; buf integer; begin loop dbms_output.put_line(a); exit when a>1000; 11 R OZDZIAŁ 2 Z ADANIA buf:=a; a:=b; b:=buf+b; end loop; end; 12 Z PODSTAW PL/SQL Rozdział 3 Zadania z obiektów 3.1 Proste typy obiektowe i tabele obiektowe 3.1.1 Typ Employee Type 1. Stworzyć typ obiektowy o nazwie Employee_Type z atrybutami EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, SALARY o typach identycznych z typami kolumn o odpowiadajacych nazwach w tabeli , HR.EMPLOYEES. Rozwiazanie , create or replace type employee_type as object ( EMPLOYEE_ID NUMBER(6, 0), FIRST_NAME VARCHAR2(20 BYTE), LAST_NAME VARCHAR2(25 BYTE), EMAIL VARCHAR2(25 BYTE), PHONE_NUMBER VARCHAR2(20 BYTE), SALARY NUMBER(8, 2) ); 2. Stworzyć tabele, obiektowa, o nazwie Employee_Objects dla obiektów typu Employee_Type. Ustanowić wiaz , klucza głównego na atrybucie o nazwie EMPLOYEE_ID. 13 R OZDZIAŁ 3 Z ADANIA Z OBIEKT ÓW Rozwiazanie , create table employee_objects of employee_type ( employee_id PRIMARY KEY ); 3. Stworzyć tabele, relacyjna, Employees_Departments z dwiema kolumnami: • EMPL typu Employee_Type, • DEPARTMENT_ID o takim samym typie jak odpowiadajaca kolumna w , tabeli HR.EMPLOYEES. Rozwiazanie , create table employees_departments ( EMPL employee_type, DEPARTMENT_ID NUMBER(4, 0) ); 4. Wypełnić tabele Employee_Objects i Employees_Departments danymi z tabeli HR.EMPLOYEES. Rozwiazanie , insert into employee_objects select employee_type(employee_id, first_name, last_name, email, phone_number, salary) from hr.employees; insert into employees_departments select employee_type(employee_id, first_name, last_name, email, phone_number, salary), department_id from hr.employees; 5. Wypisać zawartość tabel Employee_Objects i Employees_Departments przy pomocy polecenia SELECT. Rozwiazanie , select * from employee_objects; select * from employees_departments; 6. Wypisać zawartość tabeli Employee_Objects jako tabeli obiektowej z pojedyńcza, anonimowa, kolumna, korzystajac , z funkcji VALUE(). 14 R OZDZIAŁ 3 Z ADANIA Z OBIEKT ÓW Rozwiazanie , select value(p) from employee_objects p; 7. Wypisać przy pomocy SELECT tylko wartości atrybutu EMPLOYEE_ID kolumny EMPL w tabeli Employees_Departments. Rozwiazanie , select p.empl.salary from employees_departments p; 3.1.2 Typ Department Type i referencje do obiektów wierszowych 1. Stworzyć typ obiektowy o nazwie Department_Type i atrybutach DEPARTMENT_ID, DEPARTMENT_NAME, MANAGER gdzie pierwsze dwa atrybuty maja, takie same typy jak odpowiadajace ko, lumny w tabeli HR.DEPARTMENTS, natomiast atrybut MANAGER jest referencja, do obiektów typu Employee_Type. Rozwiazanie , create type department_type as object ( DEPARTMENT_ID NUMBER(4, 0), DEPARTMENT_NAME VARCHAR2(30 BYTE), MANAGER REF employee_type ); 2. Stworzyć tabele, obiektowa, o nazwie Department_Objects dla obiektów typu Department_Type z ograniczeniem PRIMARY KEY na atrybucie o nazwie DEPARTMENT_ID. Rozwiazanie , create table department_objects of department_type ( department_id PRIMARY KEY ); 3. Wypełnić tabele, Department_Objects danymi z tabeli HR.DEPARTMENTS: • W każdym wierszu atrybut MANAGER powinien być referencja, do wiersza w tabeli EMPLOYEE_OBJECTS opisujacego managera odpowiedniego , departamentu. 15 R OZDZIAŁ 3 Z ADANIA Z OBIEKT ÓW – W tabeli HR.DEPARTMENTS znajduje sie, kolumna MANAGER_ID be, daca kluczem obcym odnoszacym sie, do kolumny EMPLOYEE_ID z , , tabeli EMPLOYEES (lub EMPLOYEE_OBJECTS). • W tabeli DEPARTMENT_OBJECTS powinny znaleźć sie, dane wszystkich departamentów, także tych dla których nie określono managera. Rozwiazanie , insert into department_objects select p.department_id,p.department_name,ref(q) from hr.departments p left outer join employee_objects q on p.manager_id= q.employee_id; 4. Korzystajac , z operatora deref() wypisać dla każdego departamentu • nazwe, departamentu, • imie, i nazwisko managera. Rozwiazanie , select p.department_name,deref(p.manager).first_name, deref(p.manager).last_name from department_objects p; 3.2 Ewolucja typów 3.2.1 Dodatkowe kolumny w Employee Type 1. Korzystajac , z instrukcji ALTER TYPE dodać do typu Employee_Type dwa nowe atrybuty: • MANAGER typu referencja na Employee_Type, • DEPARTMENT typu referencja na Department_Type. Rozwiazanie , alter type Employee_Type add attribute( manager ref employee_type, department ref department_type ) cascade including table data; 2. Zweryfikować że do tabeli Employee_Objects zostały dodane nowe atrybuty. 16 R OZDZIAŁ 3 Z ADANIA Z OBIEKT ÓW Rozwiazanie , select * from employee_objects 3. Korzystajac , z tabeli HR.EMPLOYEES i instrukcji UPDATE uzupełnić dane w nowoutworzonych kolumnach tabeli Employee_Objects. Rozwiazanie , update employee_objects p set p.department=( select ref(d) from department_objects d, hr.employees e where e.employee_id = p.employee_id and d.department_id = e.department_id ),p.manager=( select ref(ee) from employee_objects ee, hr.employees f where f.employee_id = p.employee_id and ee.employee_id = f.manager_id ); 3.2.2 Dodawanie metod do typów 1. Używajac , ALTER TYPE dodać metode , MAP do typu Employee_Type o nazwie name i typie zwracanym VARCHAR2. Rozwiazanie , alter type employee_type add map member function name return varchar2 cascade; 2. Utworzyć ciało typu Employee_Type z definicja, metody name. • Metoda name powinna zwracać konkatenacje, nazwiska i imienia (w tej kolejności). Rozwiazanie , create or replace type body employee_type as map member function name return varchar2 is begin return last_name||’ ’||first_name; end; end; 3. Wypróbować zdefiniowana, metode, map: 17 R OZDZIAŁ 3 Z ADANIA Z OBIEKT ÓW select * from Employee_Objects p order by Value(p); 4. Używajac , ALTER TYPE dodać do typu Department_Type • metode, MAP o nazwie name i typie zwracanym VARCHAR2, • zwykła, bezargumentowa, metode, avg_salary zwracajac , a, wartość typu NUMBER. Rozwiazanie , alter type department_type add map member function name return varchar2 cascade; alter type department_type add member function avg_salary return number cascade; 5. Zdefiniować ciało typu Department_Type zawierajace definicje metod name , i avg_salary: • Metoda name powinna zwracać nazwe, departamentu. • Metoda avg_salary powinna zwracać średnia, płace, dla departamentu korzystajac , z danych w tabeli Employee_Objects. Rozwiazanie , create or replace type body department_type as map member function name return varchar2 is begin return department_name; end; member function avg_salary return number is average number; begin select avg(p.salary) into average from employee_objects p where p.department=( select ref(q) from department_objects q where q.department_id=self.department_id); return average; end; end; 18 R OZDZIAŁ 3 Z ADANIA Z OBIEKT ÓW 6. Wypróbować zdefiniowane metody: • Wypisać wiersze tabeli Department_Objects posortowane według wartości funkcji Value() na zmiennej krotkowej. Rozwiazanie , select * from Department_Objects p order by value(p); • Wypisać zestawienie Department_Name, Srednia Placa korzystajac , z funkcji avg_salary. Rozwiazanie , select p.department_name,p.avg_salary() from department_objects p; 7. Używajac , ALTER TYPE dodać do typu Employee_Type: • metode, (procedure) , o nazwie increase_salary i pojedyńczym argumencie o nazwie amount i typie NUMBER przekazywanym w trybie IN, Rozwiazanie , alter type employee_type add member procedure increase_salary(amount in number) cascade; • procedure, statyczna, o nazwie increase_salary i dwóch argumentach typu number przekazywanych w trybie IN o nazwach emplid i amount. Rozwiazanie , alter type employee_type add static procedure increase_salary(employee_id in number,amount in number) cascade; 8. Uzupełnić ciało typu employee_type o definicje procedur (metody i statycznej) increase_salary: • Metoda increase_salary powinna dodawać wartość amount do atrybutu salary obiektu na rzecz którego została wywołana. • Procedura statyczna increase_salary powinna zwiekszać o amount , wartość atrybutu salary instancji employee_type przechowywanej w tabeli employee_objects o atrybucie employee_id równym emplid używajac , metody increase_salary z poprzedniego punktu. 19 R OZDZIAŁ 3 Z ADANIA Z OBIEKT ÓW Rozwiazanie , create or replace type body employee_type as map member function name return varchar2 is begin return last_name||’ ’||first_name; end; member procedure increase_salary(amount in number) is begin salary:=salary + amount; end; static procedure increase_salary(employee_id in number, amount in number) is x employee_type; y number:=employee_id; begin select value(p) into x from employee_objects p where p.employee_id=y; x.increase_salary(amount); update employee_objects p set value(p)=x where p.employee_id=y; end; end; 9. Wypróbować statyczna, metode, increase_salary(). Rozwiazanie , declare begin employee_type.increase_salary(100,1000); end; 3.3 Dziedziczenie 3.3.1 Podtyp typu Employee Type 1. Używajac , ALTER TYPE uczynić typ Employee_Type niefinalnym. Pamietać , o klauzuli cascade convert to substitutable w ALTER TYPE. Rozwiazanie , alter type employee_type not final cascade convert to substitutable; 20 R OZDZIAŁ 3 Z ADANIA Z OBIEKT ÓW 2. Stworzyć podtyp Employee_Type o nazwie Employee_Ext_Type majacy , jeden dodatkowy atrybut o nazwie HIRE_DATE typu DATE. 3. Zmodyfikować wiersze w Employee_Objects o employee_id>179 tak aby zawierały obiekty Employee_Ext_Type. Dane do ostatniej kolumny pobrać z HR.EMPLOYEES. 4. Użyć TREAT aby wyświetlić kolumne, HIRE_DATE dla tych z obiektów wierszowych przechowywanych w tabeli Employee_Objects których faktycznym typem jest Employee_Ext_Type. Wykorzystać predykat IS OF w warunku WHERE. 21 Rozdział 4 Zadania z kolekcji 4.1 Funkcje i typy pomocnicze Zdefniniować • typ tablicowy INT_SEQ_TYPE: create type INT_SEQ_TYPE as table of integer; • i funkcje, tablicowa, INT_SEQUENCE: create function INT_SEQUENCE(a in integer,b in integer, step in integer default 1) return INT_SEQ_TYPE pipelined as i integer:=a; begin loop pipe row(i); i:=i+step; exit when i>b; end loop; end; a nastepnie wypróbować jej działanie: , 22 R OZDZIAŁ 4 Z ADANIA Z KOLEKCJI select value(p) from table(int_sequence(4,1000,42)) p; 4.2 Zadania z tabel zagnieżdżonych jednopoziomowo 4.2.1 Tablica ciag , ów liczbowych 1. Utworzyć tablice, o nazwie tbl_test z dwiema kolumnami: • nazwa – typu VARCHAR(20) i z wiezem PRIMARY KEY, , • liczby – typu INT_SEQ_TYPE. Nie zapomnieć o klauzuli STORE AS. Jako nazwe, tablicy pomocniczej do przechowywania wartości z kolumny liczby podać liczby_tbl. Rozwiazanie , create table tbl_test ( nazwa varchar(20) primary key, liczby INT_SEQ_TYPE ) nested table liczby store as liczby_tbl; 2. Wstawić do tbl_test wiersz z nazwa=’a’ i polem liczby zawierajacym , trzy liczby: 3, 2 i 9 korzystajac z notacji konstruktorowej. , Rozwiazanie , insert into tbl_test values(’recznie’, int_seq_type(3,2,9)); 3. Wstawić do tbl_test wiersz (’b’,null). Rozwiazanie , insert into tbl_test values(’b’,null); 4. Spróbować wstawić do tabeli zagnieżdżonej w kolumnie liczby w wierszu z nazwa=’b’ liczby od 5 do 12 korzystajac , z insert...select i zdefiniowanej wcześniej funkcji tablicowej int_sequence(): insert into table(select liczby from tbl_test where nazwa=’b’) 23 R OZDZIAŁ 4 Z ADANIA Z KOLEKCJI select p.column_value from table(int_sequence(5,12,1)) p; Zweryfikować że operacja kończy sie, błedem z powodu niemożliwości wyko, nania insert na tabeli atomowo null. 5. Zmienić wartość kolumny liczby w wierszu z nazwa=’b’ na tablice, pusta, przy pomocy instrukcji update i powtórzyć próbe, wstawienia wartości z poprzedniego punktu. Rozwiazanie , update tbl_test set liczby=int_seq_type() where nazwa=’b’; insert into table(select liczby from tbl_test where nazwa=’b’) select p.column_value from TABLE(int_sequence(5,12,1)) p; 6. Wstawić wiersz z nazwa=’c’ i kolumna, liczby zawierajac , a, wartości 2 oraz 9, 11, . . ., 19 (co 2). • Najpierw wstawić wiersz (’c’,int_seq_type(2)) a potem dostawić reszte, wartości korzystajac , z funkcji int_sequence(). Rozwiazanie , insert into tbl_test values(’c’,int_seq_type(2)); insert into table(select liczby from tbl_test where nazwa=’c’) select p.column_value from TABLE(int_sequence(9,20,2)) p; 7. Wstawić wartość 7 do tabeli zagnieżdżonej w wierszu z name=’b’. Rozwiazanie , insert into table( select liczby from tbl_test where nazwa=’b’ ) values(7); 8. Wyświetlić zawartość tabeli tbl_test. Rozwiazanie , select * from tbl_test; 9. Wyświetlić spłaszczona, zawartość tabeli tbl_test: 24 R OZDZIAŁ 4 Z ADANIA Z KOLEKCJI select p.nazwa,q.column_value from tbl_test p,table(p.liczby) q; 10. Wyświetlić MULTISTET UNION, MULTISET INTERSECT, MULTISET EXCEPT dla tabel zagnieżdżonych w kolumnie liczby dla name=’a’ i ’b’. Przykład: select (select p.liczby from tbl_test p where nazwa=’a’) multiset union (select p.liczby from tbl_test p where nazwa=’b’) from dual; 11. Wypróbować operator SET: select p.nazwa, set(p.liczby),p.liczby from tbl_test p; 12. Wyświetlić wszystkie liczby przechowywane w tabeli w postaci pojedyńczej kolekcji. Wykorzystać operator CAST( MULTISET . . . ): select cast(multiset( select q.column_value from tbl_test p,table(p.liczby) q ) as int_seq_type) from dual; 13. Wyświetlić ilości elementów w każdej z tabel zagnieżdżonych korzystajac , z funkcji CARDINALITY(): select p.nazwa, cardinality(p.liczby) from tbl_test p; 14. Stworzyć typ o nazwie int_tab_tab tablic zagnieżdżonych elementów typu int_seq_type. Rozwiazanie , create type int_tab_tab as table of int_seq_type; 25 R OZDZIAŁ 4 Z ADANIA Z KOLEKCJI 15. Wypróbować funkcje, POWERMULTISET(): select p.nazwa, cast(powermultiset(p.liczby) as int_tab_tab) from tbl_test p; 4.3 Tabele wielokrotnie zagnieżdżone 4.3.1 Kraje, regiony, lokalizacje 1. Zdefiniować typ obiektowy locations_type z atrybutami LOCATION_ID, STREET_ADDRESS, POSTAL_CODE, CITY, STATE_PROVINCE o tych samych typach co odpowiadajace kolumny w tabeli hr.locations. , Rozwiazanie , create type locations_type as object ( LOCATION_ID NUMBER(4, 0), STREET_ADDRESS VARCHAR2(40 BYTE), POSTAL_CODE VARCHAR2(12 BYTE), CITY VARCHAR2(30 BYTE), STATE_PROVINCE VARCHAR2(25 BYTE) ); 2. Stworzyć typ o nazwie locations_table tablic zagnieżdżonych o elementach typu locations_type. Rozwiazanie , create type locations_table as table of locations_type; 3. Zdefiniować typ obiektowy countries_type o atrybutach: • COUNTRY_ID, COUNTRY_NAME – typy takie same jak typy odpowiadaja, cych kolumn z tabeli hr.countries, • LOCATIONS – typu locations_table. Rozwiazanie , create type countries_type as object ( COUNTRY_ID CHAR(2 BYTE), 26 R OZDZIAŁ 4 Z ADANIA Z KOLEKCJI COUNTRY_NAME VARCHAR2(40 BYTE), locations locations_table ); 4. Zdefiniować typ o nazwie countries_table tabel zagnieżdżonych o elementach typu countries_type. Rozwiazanie , create type countries_table as table of countries_type; 5. Zdefiniować typ obiektowy region_type o atrybutach: • REGION_ID, REGION_NAME – typy takie same jak typy odpowiadajacych , kolumn z tabeli hr.regions, • COUNTRIES – typu countries_table. Rozwiazanie , create type region_type as object ( REGION_ID NUMBER, REGION_NAME VARCHAR2(25 BYTE), COUNTRIES COUNTRIES_TABLE ); 6. Stworzyć tabele, obiektowa, region_objects obiektów region_type. Pomocnicze tabele do przechowywania tabel zagnieżdżonych nazwać odpowiednio locations_aux_tbl i countries_aux_tbl. • Kolumny REGION_ID, COUNTRY_ID i LOCATION_ID powinny być kluczami głównymi odpowiednio zewnetrznej tabeli i zagnieżdżonych pod, tabel. Rozwiazanie , create table region_objects of region_type ( region_id PRIMARY KEY ) nested table countries store as countries_aux_tbl ( (country_id PRIMARY KEY) nested table locations store as locations_aux_tbl ( (location_id PRIMARY KEY) ) ); 7. Wypełnić tabele, region_objects danymi z tabel ze schematu HR korzystajac , z podzapytań skorelowanych i CAST(MULTISET...). 27 R OZDZIAŁ 4 Z ADANIA Z KOLEKCJI Rozwiazanie , insert into region_objects select r.region_id,r.region_name,cast(multiset( select countries_type(q.country_id,q.country_name, cast(multiset( select locations_type(p.location_id,p.street_address, p.postal_code,p.city, p.state_province) from hr.locations p where p.country_id= q.country_id ) as locations_table)) from hr.countries q where q.region_id=r.region_id ) as countries_table) from hr.regions r; 8. Wypisać całkowicie spłaszczona, zawartość tabeli region_objects. Rozwiazanie , select r.region_name,q.country_name,p.* from region_objects r,table(r.countries) q,table(q.locations) p; 4.3.2 Ewolucja typów i tabele wielokrotnie zagnieżdżone 1. Stworzyć typ obiektowy o nazwie dept_t i atrybutach DEPARTMENT_ID i DEPARTMENT_NAME których typy powinny być takie same jak typy odpowiadajacych kolumn z tabeli hr.departments. , Rozwiazanie , create type dept_t as object ( "DEPARTMENT_ID" NUMBER(4,0), "DEPARTMENT_NAME" VARCHAR2(30 BYTE) ); 2. Stworzyć typ tabela zagnieżdżona o nazwie dept_t_table elementów typu dept_t. Rozwiazanie , create type dept_t_table as table of dept_t; 3. Dodać do typu locations_type nowy atrybut typu dept_t_table o nazwie dept. Użyć klauzuli invalidate zamiast cascade. Rozwiazanie , alter type locations_type add attribute(dept dept_t_table) invalidate; 28 R OZDZIAŁ 4 Z ADANIA Z KOLEKCJI 4. Używajac , komendy alter type ... upgrade zadeklarować tabele , o nazwie depts_aux_tbl jako przechowujac , a, elementy w kolumnie dept w tabeli locations_aux_tbl. alter table locations_aux_tbl upgrade nested table dept store as depts_aux_table; 5. Używajac , kursorów i bloku PL/SQL wykonać update nowej kolumny dept we wszystkich tabelach zagnieżdżonych w kolumnie locations do zagnieżdżonej tabeli pustej typu dept_t_table (dept_t_table()). Rozwiazanie , declare cursor c1 is select value(c) from region_objects r,table(r.countries) c for update; x countries_type; begin open c1; loop fetch c1 into x; exit when c1%notfound; update table( select cc.locations from region_objects r,table(r.countries) cc where cc.country_id=x.country_id ) p set p.dept=dept_t_table(); end loop; close c1; commit; end; 6. Używajac , kursorów i bloku PL/SQL wstawić do tabel zagnieżdżonych w kolumnie dept odpowiednie dane z tabeli hr.departments. • Dla każdej lokalizacji wstawiamy do kolumny dept tylko te departamenty które znajduja, sie, w tej lokalizacji. Rozwiazanie , 29 R OZDZIAŁ 4 Z ADANIA Z KOLEKCJI declare cursor c2 is select value(l) from region_objects r,table(r.countries) c, table(c.locations) l for update; y locations_type; begin open c2; loop fetch c2 into y; exit when c2%notfound; insert into table( select l.dept from region_objects r,table(r.countries) c, table(c.locations) l where l.location_id=y.location_id ) select dept_t(p.department_id,p.department_name) from hr.departments p where p.location_id=y.location_id; end loop; close c2; commit; end; 30 Rozdział 5 Zadania z XML Schema 5.1 Instalacja EditiX Ściagn ać , , i zainstalować darmowa, wersje , edytora XML o nazwie EditiX. 5.2 Tworzenie przykładowego schematu. Napisać schemat XML opisujacy typ dokumentu XML zawierajacego informacje , , o pracownikach w departamentach, np: <hr:departments xmlns:hr="http://www.wfis.uni.lodz.pl/imie"> <hr:department id="1"> <hr:name>Finance</hr:name> <hr:employee id="1"> <hr:first_name>Donnie</hr:first_name> <hr:last_name>Darko</hr:last_name> <hr:email>ddarko@ii</hr:email> <hr:phone>0121212121</hr:phone> <hr:salary>20000</hr:salary> </hr:employee> </hr:department> </hr:departments> 31 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA zgodnie z nastepuj acymi regułami: , , 1. Element departments może zawierać dowolna, ilość elementów department. 2. Element department może zawierać dowolna, ilość elementów employee. Zwiazać przykładowy dokument XML ze schematem. , 5.3 Przechowywanie XML w repozytorium XML DB 1. W folderze public repozytorium XML DB utworzyć podfolder o nazwie be, dacej konkatenacj a imienia i nazwiska studenta. Do tego folderu b edziemy , , , sie, odwoływać dalej pod nazwa, student. DECLARE res BOOLEAN; BEGIN res:=dbms_xdb.createfolder(’/public/your_name’); IF res THEN dbms_output.put_line(’Success!!!’); ELSE dbms_output.put_line(’Failure....’); END IF; END; 2. W stworzonym w poprzednim zadaniu schemacie departments.xsd dodać: • Deklaracje, przestrzeni nazw http://xmlns.oracle.com/xdb (z prefiksem xdb) w elemencie <xs:schema>. • Adnotacje, Oracla xdb:defaultTable="DepartmentsXMLTable" w definicji elementu korzeniowego departments. 3. Wysłać zmodyfikowany schemat departments.xsd do repozytorium do folderu student przy pomocy ftp (port 2100). Logować sie, jak do bazy. 4. Obejrzeć zawartość pliku /public/student/departments.xsd w repozytorium XML DB przy pomocy przegladarki (port 8080). , 32 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA 5. Obejrzeć zawartość widoku resource_view. 6. Wyświetlić (korzystajac , z metody getClobVal() zawartość kolumny res w formie tekstu, dla pliku departments.xsd. select r.res.getClobVal() from resource_view r where any_path=’/public/your_name/departments.xsd’; 7. Wyświetlić zawartość pliku departments.xsd korzystajac , z xdburitype(). select xdburitype(’/public/your_name /departments.xsd’).getClob() from dual; 8. Zarejestrować schemat departments.xsd pod nazwa, http://www.wfis.uni.lodz.pl/kft2/student/Departments.xsd gdzie student należy zastapić przez imie, i nazwisko studenta. Użyć opcji , gentables=>false. DECLARE BEGIN dbms_xmlschema.registerSchema( ’http://www.wfis.uni.lodz.pl/ kft2/student/Departments.xsd’, XDBURIType(’/public/your_name/departments.xsd’), gentables=>false); END; 9. W folderze /sys/schemas/studxx odnaleźć zarejestrowany schemat i obejrzeć dodatkowe adnotacje. Użyć przegladarki. , 10. Zmodyfikować utworzony wcześniej przykładowy plik departments.xml zmieniajac , lokalizacje , schematu na http://www.wfis.uni.lodz.pl/kft2/student/Departments.xsd 33 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA 11. Zweryfikować że próba umieszczenia pliku w repozytorium przy pomocy ftp kończy sie, niepowodzeniem. 12. Utworzyć tabele, DepartmentsXMLTable ograniczona, do schematu http://www.wfis.uni.lodz.pl/kft2/student/Departments.xsd i do dokumentów XML których korzeniem jest element <departments>: CREATE TABLE "DepartmentsXMLTable" OF XMLType XMLSCHEMA "http://www.wfis.uni.lodz.pl/ kft2/studentxx/Departments.xsd" element "departments"; 13. Ponowić próbe, umieszczenia pliku departments.xml w repozytorium. 14. Zweryfikować że plik znajduje sie, w repozytorium XMLDB oraz we wcześniej utworzonej tabeli DepartmentsXMLTable. 5.4 Generowanie dokumentów XML z danych relacyjnych 1. Wykonać nastepuj ace zapytania: , , • select XMLElement(name "department", xmlattributes(d.department_id as "id"), d.department_name) from HR.departments d; • select XMLElement(name "department", xmlelement(name "id",d.department_id), xmlelement(name "name",d.department_name)) from HR.departments d; • select XMLAgg(XMLElement(name "department", xmlattributes(d.department_id as "id"), 34 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA d.department_name) order by d.department_name) from HR.departments d; • select XMLElement(name "departments", XMLAgg(XMLElement(name "department", xmlattributes(d.department_id as "id"), d.department_name) order by d.department_name)) from HR.departments d group by location_id; 2. Stworzyć tabele, xml-owa, o nazwie xmltest: create table xmltest of xmltype; 3. Stworzyć tabele, relacyjna, o nazwie xmlemployees o dwóch kolumnach: • employee_id o tym samym typie co typ kolumny o tej samej nazwie w tabeli hr.employees. • empl_data typu xmltype. 4. Wypełnić tabele xmltest i xmlemployees danymi korzystajac , z danych w tabelach hr.employees i hr.jobs. Dla każdego pracownika powinien zostać utworzony dokument XML z elementami takimi jak w poniższym przykładzie: <employee id="190" manager_id="122"> <first_name>Timothy</first_name> <last_name>Gates</last_name> <email>TGATES</email> <phone_number>650.505.3876</phone_number> <hire_date>1998-07-11</hire_date> <job id="SH_CLERK">Shipping Clerk</job> <salary>2900</salary> </employee> 5. Stworzyć plik XHTML z danych w tabelach HR.Employees i HR.Departments: 35 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA • Plik powinien zawierać tabele, z dwiema kolumnami: – Nazwy dapartament\’ow z nazwami departamentów, – Pracownicy z tabelami zawierajacymi imiona i nazwiska pracow, ników dla każdego departamentu. 6. Stworzyć plik XML zawierajacy dane z tabel schematu HR który spełnia , nastepuj acy schemat: , , <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" targetNamespace="www.wfis.uni.lodz.pl/kft2" xmlns="www.wfis.uni.lodz.pl/kft2"> <xs:complexType name="employee_type"> <xs:sequence> <xs:element name="first_name" type="xs:string"/> <xs:element name="last_name" type="xs:string"/> <xs:element name="email" type="xs:string"/> <xs:element name="phone_number" type="xs:string"/> <xs:element name="hire_date" type="xs:date"/> <xs:element name="job"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="id" type="xs:string"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> <xs:element name="salary" type="xs:decimal"/> </xs:sequence> <xs:attribute name="id" type="xs:decimal"/> <xs:attribute name="manager_id" type="xs:decimal"/> </xs:complexType> 36 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA <xs:complexType name="department_type"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="employee" type="employee_type" maxOccurs="unbounded" minOccurs="0"/> </xs:sequence> <xs:attribute name="id" type="xs:decimal"/> <xs:attribute name="manager_id" type="xs:decimal"/> </xs:complexType> <xs:complexType name="location_type"> <xs:sequence> <xs:element name="street_address" type="xs:string"/> <xs:element name="postal_code" type="xs:string"/> <xs:element name="city" type="xs:string"/> <xs:element name="state_province" type="xs:string"/> <xs:element name="department" type="department_type" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="id" type="xs:decimal"/> </xs:complexType> <xs:complexType name="country_type"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="location" type="location_type" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="id" type="xs:string"/> </xs:complexType> <xs:complexType name="region_type"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="country" type="country_type" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="id" type="xs:string"/> 37 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA </xs:complexType> <xs:element name="hr"> <xs:complexType> <xs:sequence> <xs:element name="REGION" type="region_type" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="unassigned"> <xs:complexType> <xs:sequence> <xs:element name="employee" type="employee_type" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> i umieścić go pod nazwa, hr.xml w utworzonym poprzednio podkatalogu folderu public w repozytorium XMLDB. 5.5 XMLPath w Oraclu 1. Porównać i zrozumieć działanie nastepuj acych poleceń: , , • SELECT Extract( xdburitype(’/public/YourName/hr.xml’).getxml(), ’//employee’) "A" FROM DUAL; • SELECT p.COLUMN_VALUE FROM TABLE( XMLSequence( Extract( 38 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA xdburitype(’/public/YourName/hr.xml’).getxml(), ’//employee’) )) p; • SELECT e.employee_id,p.* FROM xmlemployees e, TABLE( XMLSequence(Extract(e.empl,’//*’)) ) p; 2. Wypróbować nastepuj ace polecenia wykorzystujace typy uritype: , , , • select httpuritype( ’http://www.wfis.uni.lodz.pl/kft2’ ).getXML() from dual; • select dburitype(’/HR/EMPLOYEES’).getXML() from dual; 3. Wypróbować w przegladarce nastepuj ace URL-e wykorzystujace serwlet Oracla , , , , DbUriServlet i wyrażenia XPath, gdzie za server należy podstawić adres serwera: • http://server:8080/oradb/HR/EMPLOYEES • http://server:8080/oradb/HR/EMPLOYEES ?rowsettag=employees • http://server:8080/oradb/HR/EMPLOYEES /ROW/SALARY?rowsettag=employees • http://server:8080/oradb/HR/EMPLOYEES /ROW[SALARY>7000]?rowsettag=employees 39 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA 5.6 XQuery – jezyk zapytań do dokumentów XML , We wszystkich poniższych przykładach skrypt XQuery powinien być poprzedzany deklaracja, domyślnej przestrzeni nazw: declare default element namespace "http://www.wfis.uni.lodz.pl/kft2/nsbooks"; Korzystamy z pliku books.xml jako pliku do którego bed , a, wykonywane zapytania. 1. Wypróbować i zrozumieć nastepuj ace wyrażenia XPATH: , , <results> {//book} </results> <results> {//book[@series_id="1"]} </results> <results> {//book[not(@series_id)]} </results> <results> {//book[@href]} </results> <results> {//book[not(@series_id) or @href]} </results> <result> {//book/element()} </result> 40 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA <result> {//book[count(genre)>1]/title} </result> <result> {//book/genre[position() =1]} </result> <result> {//book[genre/last()>1]} </result> <result> {distinct-values(//book/genre)} </result> 2. Przykład prostej iteracji po liczbach: <iteration> { for $i in 0 to 10 return <b>{$i}</b> } </iteration> 3. Przykład iteracji po wyrażeniach zwróconych przez XPATH: <ol>{ for $i in //book[@series_id="1"]/title return <li>{$i/text()}</li> }</ol> 4. Klauzula at pozwala na uzyskanie pozycji bieżacego elementu na liście po , której iterujemy: <basic> { 41 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA for $i at $pos in (0,1,2,3,4,5,6) return <pair> <value>{$i}</value> <position>{$pos}</position> </pair> } </basic> 5. Bardziej złożony przykład wykorzystania at: <FLWOR>{ for $title at $pos in //title return <title pos="{$pos}">{xs:string($title)}</title> }</FLWOR> 6. Wyrażenie warunkowe: if(true) then "a" else "b" 7. Rozsadny przykład zastosowania wyrażenia warunkowego: , <books>{ for $book in //book return ( $book/author, $book/title, <genres>{ $book/genre[1]/text(), if(count($book/genre)>1) then ",..." else () }</genres> ) } </books> 42 R OZDZIAŁ 5 Z ADANIA Z XML S CHEMA 8. Przygotować przy pomocy XQuery, na podstawie pliku books.xml raport w XHTML taki jak w pliku przykładowym books.html. 43