Семантика двух утверждений различна:
- Первый не устанавливает значение переменной, если строка не найдена.
- Вторая всегда устанавливает переменную, в том числе и ноль, если строка не найдена.
Сканирование констант создает пустую строку (без столбцов!), Которая приведет к обновлению переменной в случае, если ничто не соответствует базовой таблице. Левое объединение гарантирует, что пустая строка сохранится в соединении. Назначение переменной можно рассматривать как происходящее в корневом узле плана выполнения.
С помощью 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;
С помощью 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;
Планы выполнения
Строка не поступает в корневой узел, поэтому назначение не происходит.
Строка всегда поступает в корневой узел, поэтому происходит присвоение переменной.
Не нужно беспокоиться о дополнительном постоянном сканировании и левом внешнем соединении с вложенными циклами. В частности, соединение является дешевым, поскольку оно гарантированно встретит одну строку на своем внешнем входе и не более одной строки (в вашем примере) на внутреннем входе.
Существуют и другие способы обеспечения того, чтобы строка генерировалась из подзапроса, чтобы обеспечить присвоение переменной. Одним из них является использование избыточного скалярного агрегата (без группировки по выражению):
-- 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;
Обратите внимание, что скалярный агрегат создает строку, даже если он не получает входных данных.
Документация:
Если инструкция SELECT не возвращает строк, переменная сохраняет свое текущее значение. Если выражение является скалярным подзапросом, который не возвращает значения, переменная устанавливается в NULL.
Для назначения переменных мы рекомендуем использовать SET @local_variable вместо SELECT @local_variable.
Дальнейшее чтение: