- 18. 2. 2018
- 21 minut ke čtení
-
- W
- M
- T
- M
- j
-
+3
Platí pro: SQL Server (všechny podporované verze) Azure SQL Database Azure SQL Managed Instance Azure Synapse Analytics Parallel Data Warehouse
Poddotaz je dotaz, který je vnořen do SELECT
, INSERT
, UPDATE
nebo DELETE
nebo v jiném poddotazu. Poddotaz lze použít kdekoli, kde je povolen výraz. V tomto příkladu se poddotaz používá jako výraz sloupce s názvem MaxUnitPrice v příkazu SELECT.
Subquery Fundamentals
Poddotaz je také nazývá se vnitřní dotaz nebo vnitřní výběr, zatímco příkaz obsahující poddotaz se také nazývá vnější dotaz nebo vnější výběr.
Mnoho příkazů Transact-SQL, které obsahují poddotazy, lze alternativně formulovat jako spojení. Další otázky lze položit pouze u poddotazů. V Transact-SQL obvykle neexistuje žádný rozdíl ve výkonu mezi příkazem, který obsahuje poddotaz, a sémanticky ekvivalentní verzí, která ho neobsahuje. V některých případech, kdy je nutné zkontrolovat existenci, však spojení přináší lepší výkon. Jinak musí být vnořený dotaz zpracován pro každý výsledek vnějšího dotazu, aby byla zajištěna eliminace duplikátů. V takových případech by přístup spojením přinesl lepší výsledky. Následuje příklad ukazující jak poddotaz SELECT
, tak i spojení SELECT
, které vrací stejnou sadu výsledků:
Poddotaz vnořený do vnějšího příkazu SELECT má následující komponenty:
- Běžný
SELECT
dotaz včetně běžných komponent seznamu select. - Pravidelná klauzule
FROM
obsahující jeden nebo více názvů tabulek nebo zobrazení. - Volitelná
WHERE
klauzule. - volitelná
GROUP BY
klauzule. - volitelná
HAVING
klauzule.
Dotaz SELECT poddotazu je vždy uzavřen v závorkách. Nemůže obsahovat klauzuli COMPUTE
nebo FOR BROWSE
a klauzuli ORDER BY
může obsahovat pouze tehdy, když je také uvedena klauzule TOP.
Poddotaz lze vnořit do klauzule WHERE
nebo HAVING
vnější SELECT
, INSERT
, UPDATE
nebo DELETE
nebo uvnitř jiného poddotazu. Je možné až 32 úrovní vnoření, i když se limit liší v závislosti na dostupné paměti a složitosti dalších výrazů v dotazu. Jednotlivé dotazy nemusí podporovat vnoření až do 32 úrovní. Poddotaz se může objevit kdekoli, kde lze použít výraz, pokud vrací jednu hodnotu.
Pokud se tabulka zobrazí pouze v poddotazu a ne ve vnějším dotazu, nelze sloupce z této tabulky zahrnout do výstup (seznam pro výběr vnějšího dotazu).
Příkazy, které obsahují poddotaz, mají obvykle jeden z těchto formátů:
- WHERE výraz IN (poddotaz)
- WHERE expression comparison_operator (subquery)
- WHERE EXISTS (subquery)
V některých příkazech Transact-SQL lze poddotaz vyhodnotit, jako by to byl nezávislý dotaz. Koncepčně jsou výsledky poddotazů nahrazeny do vnějšího dotazu (i když to nemusí být nutně způsob, jakým SQL Server ve skutečnosti zpracovává příkazy Transact-SQL s poddotazy).
Existují tři základní typy poddotazů. Ti, kteří:
- pracují na seznamech zavedených pomocí
IN
, nebo těch, které srovnávací operátor upravil pomocíANY
neboALL
. - Jsou zavedeny s nemodifikovaným srovnávacím operátorem a musí vrátit jedinou hodnotu.
- Jsou zavedeny testy existence s
EXISTS
.
Pravidla poddotazů
Na poddotaz se vztahují následující omezení:
- Seznam výběru poddotazu zavedeného operátorem porovnání může obsahovat pouze jeden výraz nebo název sloupce (kromě toho, že
EXISTS
aIN
fungují naSELECT *
nebo seznam). - Pokud klauzule
WHERE
vnějšího dotazu obsahuje název sloupce, je musí být kompatibilní se sloupcem v seznamu výběru poddotazů. - Ve vybraném seznamu poddotazů nelze použít datové typy ntext, text a obrázky.
- Protože musí vracet jednu hodnotu, poddotazy zavedené nemodifikovaným srovnávacím operátorem (jedním nenásledované klíčovým slovem ANY nebo ALL) nemůže obsahovat klauzule
GROUP BY
aHAVING
. - nelze použít u poddotazů, které zahrnují GROUP BY.
-
COMPUTE
aINTO
nelze specifikovat. -
ORDER BY
lze zadat pouze v případě, že je zadána takéTOP
. - Pohled vytvořený pomocí poddotazu nelze aktualizovat.
- Seznam výběrů poddotazů zavedených pomocí
EXISTS
podle konvence má hvězdičku ( *) místo názvu jednoho sloupce. Pravidla pro poddotaz zavedený pomocíEXISTS
jsou stejná jako pravidla pro standardní výběrový seznam, protože poddotaz zavedený pomocíEXISTS
vytváří existenci otestovat a místo dat vrátit TRUE nebo FALSE.
Kvalifikace názvů sloupců v poddotazech
V následujícím příkladu je sloupec BusinessEntityID ve WHERE
klauzule vnějšího dotazu je implicitně kvalifikována názvem tabulky v klauzuli vnějšího dotazu FROM
(Sales.Store). Odkaz na CustomerID ve vybraném seznamu poddotazu je kvalifikován klauzulí FROM
, tj. Tabulkou Sales.Customer.
Obecným pravidlem je, že názvy sloupců v příkazu jsou implicitně kvalifikovány tabulkou, na kterou odkazuje klauzule FROM
na stejné úrovni. Pokud sloupec v tabulce uvedené v klauzuli FROM
poddotazu neexistuje, je implicitně kvalifikován tabulkou, na kterou odkazuje FROM
klauzule vnějšího dotazu.
Takto vypadá dotaz se zadanými implicitními předpoklady:
Nikdy se nemýlí explicitně uvést název tabulky a vždy je možné přepsat implicitní předpoklady týkající se názvů tabulek s výslovnou kvalifikací.
Důležité
Pokud je na sloupec odkazován v poddotazu, neexistuje v tabulce, na kterou odkazuje klauzule poddotazu „s FROM
, ale existuje v tabulce, na kterou odkazuje vnější dotaz“ s FROM
klauzule, dotaz se provede bez chyby. SQL Server implicitně kvalifikuje sloupec v poddotazu s názvem tabulky ve vnějším dotazu.
Více úrovní vnoření
Poddotaz může sám obsahovat jeden nebo více poddotazů. Ve výpisu lze vnořit libovolný počet poddotazů.
Následující dotaz vyhledá jména zaměstnanců, kteří jsou zároveň prodejci.
Zde je sada výsledků.
Nejvnitřnější dotaz vrací ID prodejců. Dotaz na další vyšší úrovni je vyhodnocen pomocí těchto ID prodejních osob a vrací kontaktní ID čísla zaměstnanců. Konečně vnější dotaz používá ID kontaktů k vyhledání jmen zaměstnanců.
Tento dotaz můžete také vyjádřit jako spojení:
Mnoho dotazů lze vyhodnotit jednorázovým provedením poddotazu a dosazením výsledné hodnoty nebo hodnot do klauzule WHERE
vnějšího dotazu. V dotazech, které obsahují korelovaný poddotaz (také známý jako opakující se poddotaz), poddotaz závisí na vnějším dotazu na jeho hodnoty. To znamená, že poddotaz je prováděn opakovaně, jednou pro každý řádek, který může být vybrán vnějším dotazem. Tento dotaz načte jednu instanci každého křestního jména a příjmení každého zaměstnance, pro které je bonus v tabulce SalesPerson 5000 a pro který identifikační čísla zaměstnanců se v tabulkách Zaměstnanec a Prodejce shodují.
Zde je sada výsledků.
Předchozí poddotaz v tomto příkazu nelze vyhodnotit nezávisle na vnějším dotazu. Potřebuje hodnotu pro Employee.BusinessEntityID, ale tato hodnota se mění, když SQL Server zkoumá různé řádky v Employee.
Přesně takhle dotaz je vyhodnocen: SQL Server považuje každý řádek tabulky zaměstnanců za zahrnutí do výsledků nahrazením hodnoty v každém řádku do vnitřního dotazu. Například pokud SQL Server nejprve prozkoumá řádek pro Syed Abbas
, proměnná Employee.BusinessEntityID má hodnotu 285, kterou nahrazuje SQL Server utes do vnitřního dotazu.
Výsledek je 0 (Syed Abbas
nedostal bonus, protože je nikoli prodejce), takže vnější dotaz bude vyhodnocen jako:
Protože je to nepravda, řádek pro Syed Abbas
není zahrnut ve výsledcích.