A semântica das duas instruções é diferente:
- O primeiro não define o valor da variável se nenhuma linha for encontrada.
- O segundo sempre define a variável, incluindo null se nenhuma linha for encontrada.
A Varredura constante produz uma linha vazia (sem colunas!) Que resultará na atualização da variável caso nada corresponda à tabela base. A junção esquerda garante que a linha vazia sobreviva à junção. A atribuição de variável pode ser pensada como acontecendo no nó raiz do plano de execução.
Usando 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;
Usando 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;
Planos de execução
Nenhuma linha chega ao nó raiz, portanto, nenhuma atribuição ocorre.
Uma linha sempre chega ao nó raiz, portanto ocorre a atribuição de variáveis.
A varredura constante constante e a junção externa esquerda dos loops aninhados não são motivo de preocupação. A junção, em particular, é barata, pois é garantido que você encontre uma linha em sua entrada externa e, no máximo, uma linha (no seu exemplo) na entrada interna.
Existem outras maneiras de garantir que uma linha seja gerada a partir da subconsulta para garantir que uma atribuição de variável ocorra. Uma é usar um agregado escalar redundante (nenhum grupo por cláusula):
-- 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;
Observe que o agregado escalar produz uma linha, mesmo que não receba entrada.
Documentação:
Se a instrução SELECT não retornar linhas, a variável manterá seu valor presente. Se expressão for uma subconsulta escalar que não retorna valor, a variável é configurada como NULL.
Para atribuir variáveis, recomendamos que você use SET @local_variable em vez de SELECT @local_variable.
Leitura adicional: