Principes de base des sous-requêtes
Une sous-requête est une requête qui est imbriquée dans une instruction SELECT, INSERT, UPDATE ou DELETE, ou dans une autre sous-requête. Une sous-requête peut être utilisée partout où une expression est autorisée. Dans l'exemple suivant, une sous-requête est utilisée comme expression de colonne appelée MaxUnitPrice dans une instruction SELECT.
USE AdventureWorks;
GO
SELECT Ord.SalesOrderID, Ord.OrderDate,
(SELECT MAX(OrdDet.UnitPrice)
FROM AdventureWorks.Sales.SalesOrderDetail AS OrdDet
WHERE Ord.SalesOrderID = OrdDet.SalesOrderID) AS MaxUnitPrice
FROM AdventureWorks.Sales.SalesOrderHeader AS Ord
Une sous-requête est également appelée « requête interne » ou « sélection interne » et l'instruction qui la contient est aussi appelée « requête externe » ou « sélection externe ».
Il est souvent possible d'exprimer sous la forme d'une jointure une instruction Transact-SQL qui contient une sous-requête. D'autres questions peuvent uniquement être posées par le biais de sous-requêtes. Dans Transact-SQL, les performances ne varient généralement pas, que vous utilisiez une instruction comportant une sous-requête ou que vous ayez recours à une syntaxe sémantiquement équivalente qui n'en contient pas. Toutefois, lorsque vous devez vérifier l'existence, une jointure offre de meilleures performances. En effet, la requête imbriquée doit être traitée pour chaque résultat de la requête externe de façon à éliminer les doublons. Dans de tels cas, une jointure donnera de meilleurs résultats. L'exemple suivant présente une sous-requête et une jointure SELECT qui retournent le même ensemble de résultats :
/* SELECT statement built using a subquery. */
SELECT Name
FROM AdventureWorks.Production.Product
WHERE ListPrice =
(SELECT ListPrice
FROM AdventureWorks.Production.Product
WHERE Name = 'Chainring Bolts' )
/* SELECT statement built using a join that returns
the same result set. */
SELECT Prd1. Name
FROM AdventureWorks.Production.Product AS Prd1
JOIN AdventureWorks.Production.Product AS Prd2
ON (Prd1.ListPrice = Prd2.ListPrice)
WHERE Prd2. Name = 'Chainring Bolts'
Une sous-requête imbriquée dans l'instruction SELECT externe comporte les éléments suivants :
une instruction SELECT régulière constituée des éléments standard d'une liste de sélection ;
une clause FROM régulière comportant les noms d'une ou plusieurs tables ou vues ;
une clause WHERE facultative ;
une clause GROUP BY facultative ;
une clause HAVING facultative.
La requête SELECT d'une sous-requête se place toujours entre parenthèses. Elle ne peut pas contenir de clause COMPUTE ou FOR BROWSE et peut inclure une clause ORDER BY uniquement lorsqu'une clause TOP est également spécifiée.
Une sous-requête peut être imbriquée dans une clause WHERE ou HAVING d'une instruction externe SELECT, INSERT, UPDATE, DELETE ou dans une autre sous-requête. Vous pouvez aller jusqu'à 32 niveaux d'imbrication mais cette limite dépend de la mémoire disponible et de la complexité des autres expressions constituant la requête. Les requêtes individuelles, pour leur part, n'acceptent pas toujours 32 niveaux d'imbrication. Une sous-requête peut apparaître à tout endroit où une expression est autorisée, à condition de ne retourner qu'une seule valeur.
Si une table apparaît uniquement dans une sous-requête et pas dans la requête externe, les colonnes de cette table ne peuvent pas figurer dans les résultats (la liste SELECT de la requête externe).
Les instructions contenant une sous-requête se présentent généralement sous une des formes suivantes :
WHERE expression [NOT] IN (subquery)
WHERE expression comparison_operator [ANY | ALL] (subquery)
WHERE [NOT] EXISTS (subquery)
Dans certaines instructions Transact-SQL, la sous-requête peut être évaluée comme s'il s'agissait d'une requête indépendante. Théoriquement, les résultats de la sous-requête viennent s'insérer dans la requête externe (bien que ce ne soit pas nécessairement comme cela que MicrosoftSQL Server traite en réalité les instructions Transact-SQL comportant des sous-requêtes).
Il existe trois sous-requêtes de base :
les sous-requêtes qui opèrent sur des listes, introduites par IN ou par un opérateur de comparaison modifié par ANY ou ALL ;
les sous-requêtes introduites par un opérateur de comparaison non modifié et qui doivent retourner une valeur unique ;
les sous-requêtes introduites par EXISTS qui constituent des tests d'existence.