Rozdział 5 Podzapytania Podzapytania Podzapytania
Transkrypt
Rozdział 5 Podzapytania Podzapytania Podzapytania
Podzapytania • Podzapytanie jest poleceniem SELECT zagnieżdżonym w innym poleceniu SELECT. Podzapytanie może wystąpić wszędzie tam, gdzie system spodziewa się zbioru wartości, czyli w klauzulach SELECT, FROM, WHERE, HAVING. • Ogólny format zagnieżdżania zapytań: Rozdział 5 Podzapytania • Operatorem może być: • = <> < > <= >= • IN • ANY, ALL podzapytania proste i skorelowane, podzapytania w klauzuli SELECT i FROM, klauzula WITH, operatory ANY, ALL i EXISTS, zapytania hierarchiczne UWAGA! SELECT atrybut1, atrybut2, ... FROM relacja WHERE atrybutn operator (SELECT atrybuti, atrybutj FROM relacja WHERE warunek); W podzapytaniu nie może wystąpić klauzula ORDER BY (wyjątek – podzapytanie w klauzuli FROM) (c) Instytut Informatyki Politechniki Poznańskiej 1 Wyznacz pracownika zarabiającego najmniej w instytucie SELECT nazwisko, etat, placa_pod FROM pracownicy WHERE placa_pod = (SELECT MIN(placa_pod) FROM pracownicy); • 2 Podzapytania wyznaczające wiele krotek (1) Podzapytania wyznaczające jedną krotkę • (c) Instytut Informatyki Politechniki Poznańskiej • Wyświetl nazwiska i płace pracowników, zatrudnionych w zespołach o nazwach "ADMINISTRACJA" lub "ALGORYTMY". 208 SELECT nazwisko, placa_pod, placa_dod FROM pracownicy 10 WHERE id_zesp IN 40 (SELECT id_zesp FROM zespoly WHERE nazwa in ('ALGORYTMY','ADMINISTRACJA')); Wyznacz najgorzej zarabiającego asystenta SELECT nazwisko, etat, placa_pod FROM pracownicy WHERE etat = ‘ASYSTENT’ AND placa_pod = (SELECT MIN(placa_pod) FROM pracownicy WHERE etat=‘ASYSTENT’); (c) Instytut Informatyki Politechniki Poznańskiej 371 3 (c) Instytut Informatyki Politechniki Poznańskiej 4 Podzapytania wyznaczające wiele krotek (2) Podzapytania wyznaczające wiele krotek (3) • Operator ANY • stosowany z operatorami logicznymi, warunek jest prawdziwy jeśli jest spełniony dla jakiejkolwiek wartości zwróconej przez podzapytanie. • Wyświetl nazwiska najgorzej zarabiających pracowników w każdym zespole SELECT nazwisko, etat, placa_pod FROM pracownicy WHERE (placa_pod, id_zesp) IN (SELECT MIN(placa_pod), id_zesp FROM pracownicy GROUP BY id_zesp); 410 10 371 20 208 30 1350 40 (c) Instytut Informatyki Politechniki Poznańskiej SELECT nazwisko, placa_pod, etat, id_zesp FROM pracownicy WHERE placa_pod > ANY (SELECT DISTINCT placa_pod FROM pracownicy WHERE id_zesp = 30); • Operator ALL • stosowany z operatorami logicznymi, warunek jest prawdziwy jeśli jest spełniony dla wszystkich wartości zwróconych przez podzapytanie. SELECT nazwisko, placa_pod, etat, id_zesp FROM pracownicy WHERE placa_pod > ALL (SELECT DISTINCT placa_pod FROM pracownicy WHERE id_zesp = 30); 5 Najczęściej spotykane błędy (c) Instytut Informatyki Politechniki Poznańskiej 6 Podzapytania w klauzuli HAVING • Lista atrybutów w klauzuli SELECT podzapytania jest niezgodna z listą atrybutów w warunku: SELECT nazwisko, etat, placa_pod FROM pracownicy WHERE id_zesp = (SELECT nazwisko, id_zesp FROM pracownicy WHERE nazwisko=‘SLOWINSKI’ ); • Wyświetl te zespoły, w których średnia płaca podstawowa jest większa niż średnia płaca w całym instytucie. SELECT z.nazwa, AVG(p.placa_pod) AS srednia FROM pracownicy p, zespoly z WHERE p.id_zesp = z.id_zesp GROUP BY z.nazwa HAVING AVG(p.placa_pod) > (SELECT AVG(placa_pod) FROM pracownicy); ORA-00913: za duża liczba wartości • Podzapytanie zwraca więcej niż jeden wiersz a w warunku użyto operatora przewidzianego do porównywania wartości skalarnych: SELECT nazwisko, etat, placa_pod FROM pracownicy WHERE placa_pod = (SELECT MAX(placa_pod) FROM pracownicy GROUP BY id_zesp ); ORA-01427: jednowierszowe podzapytanie zwraca więcej niż jeden wiersz (c) Instytut Informatyki Politechniki Poznańskiej 7 (c) Instytut Informatyki Politechniki Poznańskiej 8 Wielopoziomowe zagnieżdżanie zapytań Reguły zagnieżdżania podzapytań • W podzapytaniu nie używamy klauzuli ORDER BY, klauzula ORDER BY może wystąpić wyłącznie jako ostatnia klauzula najbardziej zewnętrznego zapytania. • Liczba oraz typy atrybutów występujących w klauzuli SELECT podzapytania musi być zgodna z liczbą i typem atrybutów użytych w warunku zapytania zewnętrznego. • Podzapytania są zawsze wykonywane w kolejności od najgłębiej zagnieżdżonego do najbardziej zewnętrznego. • Podzapytania mogą się znaleźć w dowolnym miejscu w klauzuli WHERE. • Wyświetlić nazwiska i płace pracowników, zarabiających więcej niż wynosi maksymalna płaca w zespole o nazwie ALGORYTMY SELECT nazwisko, placa_pod FROM pracownicy WHERE placa_pod > (SELECT MAX (placa_pod) FROM pracownicy WHERE id_zesp = (SELECT id_zesp FROM zespoly WHERE nazwa = 'ALGORYTMY')); 1350 SELECT * FROM pracownicy WHERE (SELECT MIN(placa_pod) FROM pracownicy) = placa_pod; 40 (c) Instytut Informatyki Politechniki Poznańskiej SELECT * FROM pracownicy WHERE (SELECT MAX(placa_pod) FROM pracownicy WHERE etat = 'PROFESOR' ) * 0.5 <= placa_pod; 9 (c) Instytut Informatyki Politechniki Poznańskiej Podzapytanie skorelowane (1) Podzapytanie skorelowane (2) • Cechy • Podzapytanie skorelowane jest wykonywane dla każdej krotki przeglądanej przez zapytanie nadrzędne • Podzapytanie skorelowane operuje na wartościach atrybutów przekazanych przez zapytanie nadrzędne • Podzapytanie skorelowane zawsze posiada odwołanie do atrybutu zapytania nadrzędnego SELECT atrybuta, atrybutb, ... FROM relacja WHERE atrybutn >= (SELECT atrybutj FROM relacja WHERE atrybutj = atrybutb); (c) Instytut Informatyki Politechniki Poznańskiej 10 Polecenie SELECT z podzapytaniem skorelowanym wykonywane jest następująco: 1. 2. 3. 4. • pobranie krotki Kn przez zapytanie nadrzędne wykonanie podzapytania na podstawie wartości z krotki Kn zaakceptowanie bądź odrzucenie krotki Kn pobranie kolejnej krotki Kn+1 przez zapytanie nadrzędne i powtórzenie kroków 2-4 Przykład: Wyświetl nazwiska pracowników zarabiających powyżej średniej dla swojego zespołu. SELECT p.nazwisko, p.placa_pod FROM pracownicy p WHERE p.placa_pod > (SELECT AVG(placa_pod) FROM pracownicy WHERE id_zesp = p.id_zesp); zapytanie nadrzędne podzapytanie skorelowane 11 (c) Instytut Informatyki Politechniki Poznańskiej 12 Operator EXISTS Podzapytanie skorelowane (3) P Operatory EXISTS, NOT EXISTS • Operator zwraca wartość TRUE jeżeli podzapytanie zwraca jakąkolwiek wartość. Podzapytanie nie musi zwracać wartości z bazy danych, równie dobrze może zwracać dowolny literał. Pracownicy NAZWISKO LECH CZECH RUS PIAST PLACA_POD 300 400 400 500 ID_ZESP 1 1 2 2 NAZWISKO LECH CZECH RUS PIAST PLACA_POD 300 400 400 500 ID_ZESP 1 1 2 2 SELECT id_prac, nazwisko, etat, id_zesp FROM pracownicy p WHERE EXISTS (SELECT id_prac FROM pracownicy WHERE id_szefa = p.id_prac); SELECT nazwisko, placa_pod, id_zesp FROM pracownicy p WHERE placa_pod > (SELECT AVG(placa_pod) FROM pracownicy WHERE id_zesp = p.id_zesp); (c) Instytut Informatyki Politechniki Poznańskiej SELECT nazwisko, etat, id_zesp FROM pracownicy p WHERE NOT EXISTS (SELECT 1 FROM zespoly WHERE id_zesp = p.id_zesp); 13 14 Podzapytania w klauzuli FROM Podzapytania w klauzuli SELECT Zapytanie, które zwraca dokładnie jedną wartość, jest poprawnym wyrażeniem i może być wykorzystane wszędzie tam, gdzie SQL oczekuje wyrażenia, np. w klauzuli SELECT Wynik podzapytania może być wykorzystany jako wejściowy zbiór danych dla innego zapytania. Stąd w klauzuli FROM zamiast nazwy relacji można umieścić podzapytanie. W takim podzapytaniu dopuszczalne jest użycie klauzuli ORDER BY. SELECT nazwa, (SELECT MAX(placa_pod) FROM pracownicy WHERE id_zesp = z.id_zesp ) AS max_placa FROM zespoly z; Przykład: wyświetl nazwiska pracowników, którzy zarabiają więcej niż średnia płaca w zespole, w którym pracują SELECT nazwisko, placa_pod, srednia_placa_w_zespole FROM (SELECT id_zesp, AVG(placa_pod) as srednia_placa_w_zespole FROM pracownicy GROUP by id_zesp) z JOIN pracownicy p ON z.id_zesp = p.id_zesp WHERE placa_pod > srednia_placa_w_zespole; SELECT p.nazwisko, (SELECT nazwisko FROM pracownicy WHERE id_prac = p.id_szefa ) AS szef FROM pracownicy p ORDER BY nazwisko; (c) Instytut Informatyki Politechniki Poznańskiej (c) Instytut Informatyki Politechniki Poznańskiej 15 (c) Instytut Informatyki Politechniki Poznańskiej 16 Klauzula WITH – przykłady (1) Klauzula WITH Poszczególnym podzapytaniom można nadawać nazwy w celu uproszczenia składni zapytania. Służy do tego klauzula WITH SELECT nazwa, SUM(placa_pod) AS suma_plac FROM pracownicy p JOIN zespoly USING (id_zesp) GROUP BY nazwa HAVING 2 >= (SELECT COUNT(SUM(placa_pod)) FROM pracownicy JOIN zespoly USING (id_zesp) GROUP BY nazwa HAVING SUM(placa_pod) > SUM(p.placa_pod)) ORDER BY suma_plac DESC; WITH prac_zesp AS (SELECT nazwa, nazwisko, etat, placa_pod FROM pracownicy JOIN zespoly USING (id_zesp)) SELECT * FROM prac_zesp WHERE placa_pod > 1200; WITH zespoly_stat AS (SELECT nazwa, SUM(placa_pod) AS suma_plac FROM pracownicy JOIN zespoly USING (id_zesp) GROUP by nazwa) SELECT * FROM zespoly_stat s WHERE 2 >= (SELECT COUNT(*) FROM zespoly_stat WHERE suma_plac > s.suma_plac) ORDER BY suma_plac DESC; WITH profesorowie AS (SELECT * FROM pracownicy WHERE etat = 'PROFESOR'), asystenci AS (SELECT * FROM pracownicy WHERE etat = 'ASYSTENT') SELECT * FROM profesorowie pr WHERE EXISTS (SELECT * FROM asystenci WHERE id_szefa = pr.id_prac); (c) Instytut Informatyki Politechniki Poznańskiej 17 Klauzula WITH – przykłady (2) 18 Zapytania hierarchiczne – składnia Oracle SELECT nazwisko, nazwa FROM pracownicy JOIN zespoly USING (id_zesp) WHERE 3 <= (SELECT COUNT(*) FROM pracownicy WHERE id_zesp = ???); • Zapytania hierarchiczne pozwalają na rekurencję w relacjach zawierających dane hierarchiczne • Pseudokolumna LEVEL reprezentuje poziom rekurencji w drzewie hierarchii • Operator PRIOR służy do odwoływania się do rodzica danego węzła • Klauzula START WITH definiuje korzeń drzewa WITH zespoly_prac AS (SELECT nazwisko, nazwa, id_zesp FROM pracownicy JOIN zespoly USING (id_zesp)) SELECT nazwisko, nazwa FROM zespoly_prac zp WHERE 3 <= (SELECT COUNT(*) FROM pracownicy WHERE id_zesp = zp.id_zesp); SELECT id_prac, id_szefa, nazwisko, LEVEL FROM pracownicy CONNECT BY PRIOR id_prac = id_szefa START WITH nazwisko = 'WEGLARZ'; SELECT nazwisko, nazwa FROM (SELECT nazwa, nazwisko, id_zesp FROM pracownicy JOIN zespoly USING(id_zesp)) zp WHERE 3 <= (SELECT COUNT(*) FROM pracownicy WHERE id_zesp = zp.id_zesp); (c) Instytut Informatyki Politechniki Poznańskiej (c) Instytut Informatyki Politechniki Poznańskiej SELECT id_prac, id_szefa, nazwisko, LEVEL FROM pracownicy CONNECT BY PRIOR id_prac = id_szefa START WITH etat = 'PROFESOR'; 19 (c) Instytut Informatyki Politechniki Poznańskiej 20 Zapytania hierarchiczne – składnia standardowa • W Oracle wspierana od Oracle 11g Release 2 WITH podwladni100 (id_prac, id_szefa, nazwisko, poziom) AS (SELECT id_prac, id_szefa, nazwisko, 1 poziom FROM pracownicy WHERE id_prac = 100 UNION ALL SELECT p.id_prac, p.id_szefa, p.nazwisko, poziom+1 FROM podwladni100 s JOIN pracownicy p ON s.id_prac = p.id_szefa) SELECT id_prac, id_szefa, nazwisko, poziom FROM podwladni100; • Rekurencyjna klauzula WITH musi używać operacji UNION ALL • Rekurencyjna klauzula WITH musi mieć listę aliasów kolumn (c) Instytut Informatyki Politechniki Poznańskiej 21