Inspiracja , wiedza , realizacja
Jsystems

W przebudowie

Login



Java

Oracle

Linux

Android

PostgreSQL

Microsoft SQL Server

Podzapytania

Rafał Czarkowski
Data dodania: Jun 21, 2016
Data aktualizacji: Jun 21, 2016

Podzapytania (zapytania zagnieżdżone), to nic innego jak instrukcje select, umieszczone wewnątrz innych instrukcji select.

Podzapytanie może być użyte w dowolnej klauzuli


Podzapytania w klauzuli WHERE


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 max(ListPrice) from SalesLT.Product;




W wyniku zapytania wyświetlona została maksymalna cena produktu.


select ProductID, Name, ListPrice, ProductCategoryID, ProductModelID

from SalesLT.Product where ListPrice=(select avg(ListPrice) from SalesLT.Product);




W tym przykładzie jako podzapytanie użyte zostało wcześniejsze zapytanie zwracające maksymalną cenę produktu i wyświetlone zostały wszystkie produkty w tej cenie.

Przykład logiki konstrukcji takich złożonych zapytań. Chcemy wybrać wszystkie produkty które kosztują więcej niż wynośi średnia cena za produkt w sklepie – tych którzy zawyżają średnią cenę. W tym celu najpierw musimy obliczyć średnią cenę produktu w sklepie a następnie ten wynik porównać z nami innych produktów. Średnia cena produktu wynosi 744,5952 co wiemy dzięki temu zapytaniu:


select avg(ListPrice) from SalesLT.Product;




W wyniku zapytania wyświetlona została średnia cena produktu.


Teraz to zapytanie musimy „zamontować” do naszego głównego zapytania jako element warunku:


select ProductID, Name, ListPrice, ProductCategoryID, ProductModelID

from SalesLT.Product where ListPrice>(select avg(ListPrice) from SalesLT.Product);




W wyniku zapytania wyświetlone zostały produkty, których cena jest wyższa od średniej ceny produktu.

W tym wypadku obliczenie średniej realizowane jest w pierwszej kolejności, a dopiero po nim wykonywane jest porównanie ceny każdego produktu osobno z tą średnią.


Podzapytania w klauzuli FROM


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.


select Name, Color, ListPrice from 
(select Name, Color, ListPrice from SalesLT.Product where Color=‘Red’) wynik_podzapytania;




W tym zapytaniu najpierw zostało wykonane (pod)zapytanie pobierające z tabeli dane o nazwie, kolorze i cenie danego produktu, dla produktów w kolorze czerwonym. A następnie z niego pobrane zostały te same informacje, jedynie z uwzględnieniem produktów których cena jest niższa od 1000.


Podzapytania w klauzuli SELECT


Podzapytania można też umieszczać w klauzuli select pod warunkiem, że są to podzapytania zwracające dokładnie jeden wiersz i dokładnie jedną kolumną.


select Name, ListPrice, (select max(ListPrice) from SalesLT.Product) MaksymalnaCena,
((select max(ListPrice) from SalesLT.Product) - ListPrice) Różnica from SalesLT.Product;




Wyświetlona została nazwa produktu, jego cena, najwyższa cena za produkt w sklepie oraz różnica pomiędzy ceną najwyższą a ceną danego produktu przy pomocy podzapytania w klauzuli select.


Podzapytania skorelowane


Dotychczas wynik podzapytania wyliczany był tylko raz. Co prawda np. w ostatnim przykładzie wynik wyliczenia wykorzystywał zawartość wiersza w zapytaniu nadrzędnym, ale podzapytanie nie musiało być przeliczane dla każdego wiersza osobno. W przeciwnym wypadku byłoby to zapytanie skorelowane. Najlepiej będzie to wyjaśnić na przykładach:


select Name, ListPrice, (select avg(ListPrice) from SalesLT.Product T2),
from SalesLT.Product T1;




Powyższy przykład to jeszcze nie jest zapytanie skorelowane. Średnia została wyliczona raz i nie ma nic wspólnego z wierszem, w którym jest wyświetlana.


select Name, ListPrice, (select avg(ListPrice) from SalesLT.Product T2),
from SalesLT.Product T1;




Wyświetlamy nazwę produktu, cenę oraz średnią cenę ale tym razem nie w całym sklepie a dla danej kategorii produktów.

Należy zwrócić uwagę, że podzapytanie musi niejako sprawdzić” jaki jest numer kategorii danego produktu by mogło zostać wyliczone. Do zewnętrznego wiersza zewnętrznego zapytania odnosi się poprzez alias. Takie podzapytanie nazywamy podzapytaniem skorelowane.


Podzapytania powiązane


Wykonanie poprzednio opisanych podzapytań sprowadza się do wykonania wewnętrznej instrukcji select i zwrócenia obliczonego wyniku do zapytania zewnętrznego.

Podzapytania powiązane, wykonywane są według innego schematu. W tym wypadku podzapytanie wykonywane jest dla każdego wiersza wyniku zapytania zewnętrznego i może być z nim porównywane. Podzapytanie powiązane jest przykładem dynamicznego złączenia wyniku zapytania z każdym kolejnym wierszem wyniku zapytania zewnętrznego.

Podzapytanie powiązane jako przykład dynamicznego złączenia można łatwo rozpoznać po tym, że kolumna wyniku podzapytania jest porównywana z kolumną wyniku zapytania zewnętrznego. Niezależne wykonanie zewnętrznego zapytania jest w tym przypadku niemożliwe.

Dodatkowo z opisu wykonywania przez serwer baz danych podzapytań powiązanych wynika, że mogą być one używane jako funkcjonalne odpowiedniki złączenia tabel. Takie zastosowanie podzapytania pokazuje poniższy przykład.


select * from SalesLT.ProductCategory;




Wyświetlenie wszystkiego z tabeli SalesLT.ProductCategory.


select ProductID, Name, Color, ListPrice from SalesLT.Product where ProductCategoryID in (select ProductCategoryID from SalesLT.ProductCategory where ParentProductCategoryID=2);




Zapytanie zwracające dane o towarach, których nadrzędną kategorią są rowery, warunek ten sprawdzany jest przez podzapytanie.

select count(*) from SalesLT.Product.ProductID where exists (select ProductID from SalesLT.Product where ProductID=SalesLT.Product.ProductID and ProductID=708);




Za pomocą operatora exists sprawdzamy czy podzapytanie generuje jakiekolwiek wiersze. W tym przypadku widzimy, że produkt o identyfikatorze 707 występuje w podzapytaniu (w tabeli SalesLT.Product) i wystąpił w zapytaniu (w tabeli SalesLT.SalesOrderDetail) siedem razy.