Utiliser des sous-requêtes scalaires ou à valeurs multiples

Effectué

Une sous-requête scalaire est une instruction SELECT interne dans une requête externe, écrite pour retourner une valeur unique. Les sous-requêtes scalaires peuvent être utilisées n’importe où dans une instruction T-SQL externe où une expression à valeur unique est autorisée, par exemple dans une clause SELECT, une clause WHERE, une clause HAVING ou même une clause FROM. Elles peuvent également être utilisées dans les instructions de modification de données, comme UPDATE ou DELETE.

Les sous-requêtes à valeurs multiples, comme le nom le suggère, peuvent retourner plusieurs lignes. Toutefois, elles renvoient toujours une seule colonne.

Sous-requêtes scalaires

Supposons que vous souhaitiez récupérer les détails de la dernière commande qui a été placée, en partant du principe qu’il s’agit de celle ayant la valeur SalesOrderID la plus élevée.

Pour trouver la valeur SalesOrderID la plus élevée, vous pouvez utiliser la requête suivante :

SELECT MAX(SalesOrderID)
FROM Sales.SalesOrderHeader

Cette requête retourne une valeur unique qui indique la valeur la plus élevée d’un OrderID dans la table SalesOrderHeader.

Pour obtenir les détails de cette commande, vous devrez peut-être filtrer la table SalesOrderDetails en fonction de la valeur renvoyée par la requête ci-dessus. Vous pouvez accomplir cette tâche en imbriquant la requête pour récupérer le SalesOrderID maximal dans la clause WHERE d’une requête qui récupère les détails de la commande.

SELECT SalesOrderID, ProductID, OrderQty
FROM Sales.SalesOrderDetail
WHERE SalesOrderID = 
   (SELECT MAX(SalesOrderID)
    FROM Sales.SalesOrderHeader);

Pour écrire une sous-requête scalaire, tenez compte des instructions suivantes :

  • Pour indiquer une requête sous la forme d’une sous-requête, mettez-la entre parenthèses.
  • Plusieurs niveaux de sous-requêtes sont pris en charge en Transact-SQL. Dans ce module, nous envisageons uniquement les requêtes à deux niveaux (une requête interne au sein d’une requête externe), mais jusqu’à 32 niveaux sont pris en charge.
  • Si la sous-requête ne retourne aucune ligne (ensemble vide), le résultat de la sous-requête est une valeur NULL. Si, dans votre scénario, aucune ligne n’est retournée, vous devez vous assurer que votre requête externe peut gérer correctement une valeur NULL, en plus des autres résultats attendus.
  • La requête interne doit généralement retourner une seule colonne. La sélection de plusieurs colonnes dans une sous-requête est presque toujours une erreur. La seule exception est si la sous-requête est introduite avec le mot clé EXISTS.

Une sous-requête scalaire peut être utilisée n’importe où dans une requête où une valeur est attendue, y compris la liste SELECT. Par exemple, nous pourrions étendre la requête qui extrait les détails de la commande la plus récente pour inclure la quantité moyenne d’articles commandés, afin de pouvoir comparer la quantité commandée dans la commande la plus récente avec la moyenne de toutes les commandes.

SELECT SalesOrderID, ProductID, OrderQty,
    (SELECT AVG(OrderQty)
     FROM SalesLT.SalesOrderDetail) AS AvgQty
FROM SalesLT.SalesOrderDetail
WHERE SalesOrderID = 
    (SELECT MAX(SalesOrderID)
     FROM SalesLT.SalesOrderHeader);

Sous-requêtes à valeurs multiples

Une sous-requête à valeurs multiples est adaptée pour retourner les résultats à l’aide de l’opérateur IN. L’exemple hypothétique suivant retourne les valeurs CustomerID, SalesOrderID pour toutes les commandes passées par les clients au Canada.

SELECT CustomerID, SalesOrderID
FROM Sales.SalesOrderHeader
WHERE CustomerID IN (
    SELECT CustomerID
    FROM Sales.Customer
    WHERE CountryRegion = 'Canada');

Dans cet exemple, si vous n’exécutez que la requête interne, une colonne de valeurs CustomerID est retournée, avec une ligne pour chaque client au Canada.

Dans de nombreux cas, les sous-requêtes à valeurs multiples peuvent facilement être écrites à l’aide de jointures. Par exemple, voici une requête qui utilise une jointure pour retourner les mêmes résultats que l’exemple précédent :

SELECT c.CustomerID, o.SalesOrderID
FROM Sales.Customer AS c
JOIN Sales.SalesOrderHeader AS o
    ON c.CustomerID = o.CustomerID
WHERE c.CountryRegion = 'Canada';

Comment décider si vous souhaitez écrire une requête impliquant plusieurs tables avec JOIN ou avec une sous-requête ? Parfois, cela dépend simplement de ce qui vous convient le mieux. La plupart des requêtes imbriquées qui sont facilement converties en JOIN seront de fait converties en JOIN en interne. Pour ces requêtes, il n’y a pas de différence réelle entre les deux écritures.

Vous devez garder à l’esprit que lorsque vous utilisez une requête imbriquée, les résultats retournés au client ne peuvent inclure que des colonnes de la requête externe. Par conséquent, si vous devez retourner des colonnes des deux tables, vous devez écrire la requête à l’aide de JOIN.

Enfin, il existe des situations où la requête interne doit effectuer des opérations bien plus compliquées que les récupérations simples de nos exemples. Il peut être difficile de réécrire des sous-requêtes complexes à l’aide de JOIN. De nombreux développeurs SQL estiment que les sous-requêtes fonctionnent mieux pour un traitement compliqué, car elles vous permettent de décomposer le traitement en étapes plus petites.