- 18/02/2018
- 21 minuten om te lezen
-
- W
- M
- T
- M
- j
-
+3
Is van toepassing op: SQL Server (alle ondersteunde versies) Azure SQL Database Azure SQL Managed Instance Azure Synapse Analytics Parallel Data Warehouse
Een subquery is een query die is genest in een SELECT
, INSERT
, UPDATE
, of DELETE
instructie, of in een andere subquery. Een subquery kan overal worden gebruikt waar een uitdrukking is toegestaan. In dit voorbeeld wordt een subquery gebruikt als een kolomexpressie met de naam MaxUnitPrice in een SELECT-instructie.
Subquery Fundamentals
Een subquery is ook wordt een innerlijke query of innerlijke selectie genoemd, terwijl de instructie die een subquery bevat ook een uiterlijke query of uiterlijke selectie wordt genoemd.
Veel Transact-SQL-instructies die subquery’s bevatten, kunnen als joins worden geformuleerd. Andere vragen kunnen alleen worden gesteld met subquery’s. In Transact-SQL is er meestal geen prestatieverschil tussen een instructie die een subquery bevat en een semantisch equivalente versie die dat niet doet. In sommige gevallen waarin het bestaan moet worden gecontroleerd, levert een join echter betere prestaties op. Anders moet de geneste query worden verwerkt voor elk resultaat van de buitenste query om ervoor te zorgen dat duplicaten worden verwijderd. In dergelijke gevallen zou een join-benadering betere resultaten opleveren. Het volgende is een voorbeeld van zowel een subquery SELECT
als een join SELECT
die dezelfde resultaatset retourneren:
Een subquery genest in de buitenste SELECT-instructie heeft de volgende componenten:
- Een normale
SELECT
query inclusief de reguliere selectielijstcomponenten. - Een normale
FROM
-clausule met een of meer tabel- of weergavenamen. - Een optionele
WHERE
clausule. - Een optionele
GROUP BY
clausule. - Een optionele
HAVING
-clausule.
De SELECT-query van een subquery staat altijd tussen haakjes. Het mag geen COMPUTE
of FOR BROWSE
-clausule bevatten, en mag alleen een ORDER BY
-clausule bevatten wanneer een TOP-clausule is ook gespecificeerd.
Een subquery kan worden genest in de WHERE
of HAVING
-clausule van een buitenste SELECT
, INSERT
, UPDATE
of DELETE
statement, of in een andere subquery. Er zijn maximaal 32 nesten mogelijk, hoewel de limiet varieert op basis van het beschikbare geheugen en de complexiteit van andere uitdrukkingen in de query. Afzonderlijke zoekopdrachten ondersteunen mogelijk geen nesting tot 32 niveaus. Een subquery kan overal verschijnen waar een uitdrukking kan worden gebruikt, als deze een enkele waarde retourneert.
Als een tabel alleen in een subquery voorkomt en niet in de buitenste query, kunnen kolommen uit die tabel niet worden opgenomen in de output (de geselecteerde lijst van de buitenste query).
Uitspraken die een subquery bevatten, hebben meestal een van deze formaten:
- WHERE expressie IN (subquery)
- WHERE expressie vergelijkingsoperator (subquery)
- WHERE EXISTS (subquery)
In sommige Transact-SQL-instructies kan de subquery worden geëvalueerd alsof het een onafhankelijke vraag. Conceptueel worden de resultaten van de subquery vervangen door de buitenste query (hoewel dit niet noodzakelijk is hoe SQL Server Transact-SQL-instructies met subquery’s daadwerkelijk verwerkt).
Er zijn drie basistypen subquery’s. Degenen die:
- werken op lijsten die zijn geïntroduceerd met
IN
, of die door een vergelijkingsoperator zijn gewijzigd doorANY
ofALL
. - Worden geïntroduceerd met een ongewijzigde vergelijkingsoperator en moeten een enkele waarde retourneren.
- Zijn existentie-tests geïntroduceerd met
EXISTS
.
Regels voor subquery’s
Een subquery is onderworpen aan de volgende beperkingen:
- De selectielijst van een subquery die met een vergelijkingsoperator wordt geïntroduceerd, kan slechts één uitdrukking of kolomnaam bevatten (behalve dat
EXISTS
enIN
werken opSELECT *
of een lijst, respectievelijk). - Als de
WHERE
-clausule van een externe zoekopdracht een kolomnaam bevat, moet join-compatibel zijn met de kolom in de selectielijst voor subquery’s. - De gegevenstypen ntext, text en image kunnen niet worden gebruikt in de geselecteerde lijst met subquery’s.
- Omdat ze een enkele waarde moeten retourneren, kunnen subquery’s die zijn geïntroduceerd door een ongewijzigde vergelijkingsoperator (één niet gevolgd door het zoekwoord ANY of ALL) mag
GROUP BY
enHAVING
clausules bevatten. - De
DISTINCT
zoekwoord kan niet worden gebruikt met subquery’s die GROUP BY bevatten. - De
COMPUTE
enINTO
-clausules kunnen niet worden gespecificeerd. -
ORDER BY
kunnen alleen worden gespecificeerd alsTOP
ook is gespecificeerd. - Een weergave die is gemaakt door een subquery te gebruiken, kan niet worden bijgewerkt.
- De selectielijst van een subquery die is geïntroduceerd met
EXISTS
heeft volgens afspraak een asterisk ( *) in plaats van een enkele kolomnaam. De regels voor een subquery geïntroduceerd metEXISTS
zijn dezelfde als die voor een standaard selectielijst, omdat een subquery geïntroduceerd metEXISTS
een bestaan creëert test en retourneert TRUE of FALSE, in plaats van data.
Kwalificerende kolomnamen in subquery’s
In het volgende voorbeeld geeft de BusinessEntityID-kolom in de WHERE
-clausule van de buitenste query wordt impliciet gekwalificeerd door de tabelnaam in de buitenste query FROM
-clausule (Sales.Store). De verwijzing naar CustomerID in de geselecteerde lijst van de subquery wordt gekwalificeerd door de subquery FROM
-clausule, dat wil zeggen door de tabel Sales.Customer.
De algemene regel is dat kolomnamen in een instructie impliciet worden gekwalificeerd door de tabel waarnaar wordt verwezen in de FROM
-clausule op hetzelfde niveau. Als een kolom niet voorkomt in de tabel waarnaar wordt verwezen in de FROM
-clausule van een subquery, wordt deze impliciet gekwalificeerd door de tabel waarnaar wordt verwezen in de FROM
clausule van de buitenste query.
Hier is hoe de query eruit ziet met deze impliciete aannames gespecificeerd:
Het is nooit fout om de tabelnaam expliciet te vermelden, en het is altijd mogelijk om impliciete aannames over tabelnamen met expliciete kwalificaties te negeren.
Belangrijk
Als een kolom wordt verwezen in een subquery die komt niet voor in de tabel waarnaar wordt verwezen door de subquery “s FROM
-clausule, maar bestaat in een tabel waarnaar wordt verwezen door de buitenste query” s FROM
clausule, wordt de query uitgevoerd zonder fout. SQL Server kwalificeert de kolom in de subquery impliciet met de tabelnaam in de buitenste query.
Meerdere nesten
Een subquery kan zelf een of meer subquery’s bevatten. Elk aantal subquery’s kan in een statement worden genest.
De volgende query vindt de namen van medewerkers die ook verkopers zijn.
Hier is de resultatenset.
De binnenste query retourneert de verkooppersoon-ID’s. De vraag op het volgende hogere niveau wordt geëvalueerd met deze verkooppersoon-ID’s en retourneert de contact-ID-nummers van de medewerkers. Ten slotte gebruikt de buitenste vraag de contact-ID’s om de namen van de werknemers te vinden.
U kunt deze vraag ook uitdrukken als een join:
Veel zoekopdrachten kunnen worden geëvalueerd door de subquery één keer uit te voeren en de resulterende waarde of waarden in de WHERE
-clausule van de buitenste query te vervangen. In query’s die een gecorreleerde subquery bevatten (ook bekend als een herhalende subquery), is de subquery afhankelijk van de buitenste query voor zijn waarden. Dit betekent dat de subquery herhaaldelijk wordt uitgevoerd, één keer voor elke rij die kan worden geselecteerd door de buitenste query. Deze query haalt één instantie op van de voor- en achternaam van elke werknemer waarvoor de bonus in de tabel SalesPerson 5000 is en waarvoor de werknemersidentificatienummers komen overeen in de tabellen Werknemer en Verkooppersoon.
Hier is de resultatenset.
De vorige subquery in deze instructie kan niet onafhankelijk van de buitenste query worden geëvalueerd. Er is een waarde nodig voor Employee.BusinessEntityID, maar deze waarde verandert naarmate SQL Server verschillende rijen in Employee onderzoekt.
Dat is precies hoe dit query wordt geëvalueerd: SQL Server beschouwt elke rij van de tabel Werknemer voor opname in de resultaten door de waarde in elke rij in de innerlijke query te vervangen. Als SQL Server bijvoorbeeld eerst de rij onderzoekt op Syed Abbas
, de variabele Employee.BusinessEntityID krijgt de waarde 285, die door SQL Server wordt vervangen utes in de innerlijke zoekopdracht.
Het resultaat is 0 (Syed Abbas
heeft geen bonus ontvangen omdat hij geen verkoper), dus de buitenste zoekopdracht evalueert naar:
Omdat dit niet waar is, wordt de rij voor Syed Abbas
is niet meegenomen in de resultaten.