La sémantique des deux déclarations est différente:
- Le premier ne définit pas la valeur de la variable si aucune ligne n'est trouvée.
- Le second définit toujours la variable, y compris sur null si aucune ligne n'est trouvée.
Le scan constant produit une ligne vide (sans colonnes!) Qui entraînera la mise à jour de la variable au cas où rien ne correspondrait à la table de base. La jointure gauche garantit que la ligne vide survit à la jointure. L'affectation variable peut être considérée comme se produisant au nœud racine du plan d'exécution.
En utilisant SELECT @result
-- Set initial value
DECLARE @result uniqueidentifier = {guid 'FE2CA909-1162-4C6C-A7AC-33B257E28539'};
-- @result does not change
SELECT @result = AccountId
FROM Accounts
WHERE AccountId={guid '7AD4D33C-1ED7-4183-B7F3-48C33D666525'};
SELECT @result;
En utilisant SET @result
-- Set initial value
DECLARE @result uniqueidentifier = {guid 'FE2CA909-1162-4C6C-A7AC-33B257E28539'};
-- @result set to null
SET @result =
(
SELECT AccountId
FROM Accounts
WHERE AccountId={guid '7AD4D33C-1ED7-4183-B7F3-48C33D666525'}
);
SELECT @result;
Plans d'exécution
Aucune ligne n'arrive au nœud racine, donc aucune affectation ne se produit.
Une ligne arrive toujours au nœud racine, donc l'affectation des variables se produit.
Le balayage constant supplémentaire et la jointure externe gauche des boucles imbriquées ne sont pas à craindre. La jointure en particulier est bon marché car elle est garantie de rencontrer une ligne sur son entrée externe et au plus une ligne (dans votre exemple) sur l'entrée interne.
Il existe d'autres façons de garantir qu'une ligne est générée à partir de la sous-requête pour garantir qu'une affectation de variable se produit. L'une consiste à utiliser un agrégat scalaire redondant (pas de clause group by):
-- Set initial value
DECLARE @result uniqueidentifier = {guid 'FE2CA909-1162-4C6C-A7AC-33B257E28539'};
-- @result set to null
SET @result =
(
SELECT MAX(AccountId)
FROM Accounts
WHERE AccountId={guid '7AD4D33C-1ED7-4183-B7F3-48C33D666525'}
);
SELECT @result;
Notez que l'agrégat scalaire produit une ligne même s'il ne reçoit aucune entrée.
Documentation:
Si l'instruction SELECT ne renvoie aucune ligne, la variable conserve sa valeur actuelle. Si expression est une sous-requête scalaire qui ne renvoie aucune valeur, la variable est définie sur NULL.
Pour affecter des variables, nous vous recommandons d'utiliser SET @local_variable au lieu de SELECT @local_variable.
Lectures complémentaires: