
Strona o szybkim czytaniu.
Podzapytania są bardzo wygodną metodą osiągania pożądanego wyniku w języku SQL. Stosujemy je wtedy, gdy w zapytaniu chcemy się odwołać nie do jakiejś statycznej wartości ale do wyniku zwróconego z innego zapytania.
Podzapytania proste wykonują się w ten sposób, że najpierw jeden raz wykonuje się podzapytanie, a następnie zwrócone przez nie wartości są podstawiane do zapytania zewnętrznego i wykonywane jest zapytanie zewnętrzne.
SELECT tow_nazwa,
tow_cena,
tow_podatek
FROM towary
WHERE tow_cena = (SELECT max(tow_cena)
FROM towary);
SELECT tow_nazwa,
tow_cena,
tow_podatek
FROM towary
WHERE tow_podatek = (SELECT tow_podatek
FROM towary
WHERE tow_nazwa = 'Lampka');
Podczas sprawdzania warunków w klauzuli WHERE
można stosować nie tylko operator równości.
SELECT zam_opis,
zam_data_zamowienia
FROM zamowienia
WHERE zam_data_zamowienia < (SELECT zam_data_zamowienia
FROM zamowienia
WHERE zam_numer = 490);
W jednym zapytaniu może występować kilka podzapytań.
SELECT zam_klt_id
FROM zamowienia
WHERE zam_data_zamowienia = (SELECT max(zam_data_zamowienia)
FROM zamowienia)
OR zam_data_zamowienia = (SELECT min(zam_data_zamowienia)
FROM zamowienia);
Powyższe zapytania działają tylko w przypadku, gdy podzapytanie zwraca nie więcej niż jeden wiersz. Jeżeli podzapytanie zwraca więcej wierszy, to zamiast operatora równości musimy użyć operatora IN
.
SELECT *
FROM zamowienia
WHERE zam_klt_id IN (SELECT klt_id
FROM klienci
WHERE klt_typ = 'IND');
W przypadku podzapytań wielowierszowych zamiast =
stosujemy IN
, natomiast zamiast operatorów większości i mniejszości musimy stosować operatory ANY
lub ALL
. Określają one, czy sprawdzana wartość musi być większa (mniejsza) od wszystkich wartości zwróconych przez podzapytanie czy tylko większa (mniejsza) od którejkolwiek z wartości zwróconych.
SELECT tow_nazwa,
tow_cena
FROM towary
WHERE tow_cena
> ANY (SELECT tow_cena
FROM towary T, zamowienia Z, pozycje_zamowien P
WHERE T.tow_id = P.pzm_tow_id
AND P.pzm_zam_id = Z.zam_id
AND Z.zam_numer = 899);
Podzapytanie może zwracać więcej niż jedną kolumnę. Możemy wtedy porównywać całe zbiory wartości, ale jesteśmy ograniczeni tylko do operatora równości w przypadku podzapytań jednowierszowych i do operatora IN
w przypadku podzapytań zwracających wiele wierszy.
SELECT *
FROM towary
WHERE (nvl(tow_podatek, 0), tow_cena)
IN (SELECT nvl(tow_podatek, 0), min(tow_cena)
FROM towary
GROUP BY nvl(tow_podatek, 0));
Podzapytania mogą być wielokrotnie zagnieżdżane.
SELECT *
FROM klienci
WHERE klt_id
IN (SELECT zam_klt_id
FROM zamowienia
WHERE zam_data_zamowienia
= (SELECT max(zam_data_zamowienia)
FROM zamowienia));
Podzapytanie może być także użyte w klauzuli HAVING
.
SELECT nvl(tow_podatek,0), avg(tow_cena)
FROM towary
GROUP BY nvl(tow_podatek,0)
HAVING min(tow_cena) > (SELECT tow_cena
FROM towary
WHERE tow_nazwa = 'Mikrofon');
W zapytaniach zawierających podzapytania skorelowane w definicji podzapytania występuje odwołanie do wartości z zapytania zewnętrznego, tzw. korelacja.
SELECT tow_nazwa, tow_cena, nvl(tow_podatek, 0)
FROM towary T
WHERE tow_cena
>= (SELECT avg(tow_cena)
FROM towary
WHERE nvl(tow_podatek, 0) = nvl(T.tow_podatek, 0));
Zapytania z podzapytaniami skorelowanymi wykonują się zupełnie inaczej niż z podzapytaniami prostymi. Najpierw jest wykonywane zapytanie zewnętrzne, a następnie dla każdego wiersza zwróconego z zapytania zewnętrznego budowane jest podzapytanie i dla każdego wiersza z zapytania zewnętrznego wykonywane jest to podzapytanie.
Bardzo wiele zadań można zrealizować zarówno przy pomocy podzapytań prostych jak i przy pomocy podzapytań skorelowanych.
Podzapytania z operatorami EXISTS
i NOT EXISTS
są szczególnym przypadkiem podzapytań skorelowanych.
Operatorów tych używamy w przypadku, gdy nie jest dla nas ważne, jakie wartości zwraca podzapytanie, ale tylko interesuje nas, czy podzapytanie zwraca jakikolwiek wiersze.
SELECT *
FROM towary T
WHERE EXISTS (SELECT *
FROM towary
WHERE tow_tow_id = T.tow_id);
Ponieważ wartości zwracane przez podzapytanie nie mają żadnego znaczenia, to na liście SELECT w podzapytaniu może znaleźć się dowolna wartość.
SELECT *
FROM towary T
WHERE NOT EXISTS
(SELECT 1
FROM pozycje_zamowien P,
zamowienia Z
WHERE P.pzm_zam_id = Z.zam_id
AND P.pzm_tow_id = T.tow_id
AND to_char(Z.zam_data_zamowienia, 'yyyy') = '1999');
Każde zapytanie dostarcza zbioru danych uszeregowanych w postaci wierszy i kolumn. a więc w takiej postaci, w jakiej dane są przechowywane w tabelach. Można to wykorzystać wpisując podzapytanie w klauzuli FROM zapytania zewnętrznego.
W takim wypadku wynik zwrócony przez podzapytanie jest traktowany jak dynamicznie utworzona tabela, która posiada pewien określony zbiór kolumn i wierszy, do których można odwoływać się w zapytaniu zewnętrznym jak do kolumn i wierszy zwykłej, statycznej tabeli.
22% 7% pozostałe
-----.---- -----------
16 5 1
SELECT sum(T.t22) "22%", sum(T.t7) "7%", sum(T.tx) "pozostałe"
FROM (SELECT count(*) t22, 0 t7, 0 tx
FROM towary
WHERE tow_podatek = 22
UNION ALL
SELECT 0 t22, count(*) t7, 0 tx
FROM towary
WHERE tow_podatek = 7
UNION ALL
SELECT 0 t22, 0 t7, count(*) tx
FROM towary
WHERE tow_podatek NOT IN (7, 22)) T;
SELECT Z1.zam_opis "Zamowienie",
Z2.ile_pozycji "Ilość pozycji",
Z2.kwota "Kwota",
Z2.kwota*G.grc_rabat/100 "Rabat"
FROM zamowienia Z1,
(SELECT Z.zam_id,
count (*) ile_pozycji,
sum (T.tow_cena * P.pzm_ilosc) kwota
FROM zamowienia Z,
pozycje_zamowien P,
towary T
WHERE Z.zam_id = P.pzm_zam_id
AND T.tow_id = P.pzm_tow_id
AND Z.zam_data_realizacji IS NOT null
GROUP BY Z.zam_id) Z2,
grupy_cen G
WHERE Z1.zam_id = Z2.zam_id
AND Z2.kwota BETWEEN G.grc_cena_od AND G.grc_cena_do;
Aby móc odwoływać się w zapytaniu do kolumn tabeli powstałej poprzez wykonanie podzapytania należy zdefiniować alias do podzapytania oraz aliasy do kolumn podzapytania, które powstały na skutek obliczenia wyrażenia i przez to nie posiadają swojej nazwy.