La semantica delle due affermazioni è diversa:
- Il primo non imposta il valore della variabile se non viene trovata alcuna riga.
- Il secondo imposta sempre la variabile, incluso su null se non viene trovata alcuna riga.
La scansione costante produce una riga vuota (senza colonne!) Che comporterà l'aggiornamento della variabile nel caso in cui nulla corrisponda alla tabella di base. Il join sinistro garantisce che la riga vuota sopravviva al join. L'assegnazione delle variabili può essere considerata come avvenuta nel nodo principale del piano di esecuzione.
utilizzando 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;
utilizzando 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;
Piani di esecuzione
Nessuna riga arriva al nodo principale, quindi non si verifica alcuna assegnazione.
Una riga arriva sempre al nodo principale, quindi si verifica l'assegnazione variabile.
La Scansione Costante extra e la giunzione esterna sinistra dei loop nidificati non sono nulla di cui preoccuparsi. Il join, in particolare, è economico poiché garantisce di incontrare una riga sul suo input esterno e al massimo una riga (nel tuo esempio) sull'input interno.
Esistono altri modi per garantire che una riga venga generata dalla sottoquery per garantire che si verifichi un'assegnazione variabile. Uno è usare un aggregato scalare ridondante (nessuna clausola 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;
Si noti che l'aggregato scalare produce una riga anche se non riceve input.
Documentazione:
Se l'istruzione SELECT non restituisce righe, la variabile mantiene il suo valore attuale. Se expression è una sottoquery scalare che non restituisce alcun valore, la variabile è impostata su NULL.
Per l'assegnazione delle variabili, si consiglia di utilizzare SET @local_variable anziché SELECT @local_variable.
Ulteriori letture: