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