2015-12-03 1 views
1

У меня есть следующий код:Почему оператор Select не присваивает пустую строку или значение null, если она не возвращает результат?

declare @testValue nvarchar(50) = 'TEST'; 

select @testValue = 'NOTUSED' where 1 > 2; 
select @testValue; -- Outputs 'TEST' 
select @testValue = 'USED' where 2 > 1; 
select @testValue; -- Outputs 'USED' 

С выше, первое задание никогда не используется, потому что, где положение не удается. Второй выполняется правильно и возвращается.

Почему SQL не возвращает null в этом случае и присваивает значение NULL @testValue после первого присваивания, где предложение where терпит неудачу?

+0

Являются ли эти> знаки ориентированными прямо? где 2> 1 верно, верно? – mikey

+0

также значение похоже, должно быть testValue – swestner

+0

Хм. Вы правы. Я получил его назад. Первый оператор select при запуске вернет пустой набор результатов. Но @testValue никогда не устанавливается в NULL или пустую строку в этом случае. Он по-прежнему сохраняет значение «TEST». Мне любопытно, почему это происходит, и если я что-то упускаю. – SamIAm

ответ

2

Это ожидаемое поведение:

«Если ЗЕЬЕСТ не возвращает ни одной строки, переменная сохраняет свое текущее значение Если выражение является скаляром подзапрос не возвращает значение, то переменная устанавливается в NULL.»

https://msdn.microsoft.com/en-us/library/ms187330.aspx

Вы можете обойти это в вашем примере, используя подзапрос в правой части.

SELECT @testValue = (SELECT 'NOTUSED' where 1 > 2); 

Что касается того, почему именно так, я не могу сказать точно. Возможно, весь @testValue = 'NOTUSED' приравнивается к NULL вместо правой части 'NOTUSED' части инструкции, и это предотвращает установку параметра. Не напрямую, но я могу сказать, что мне потребовалось некоторое время, чтобы убедить себя в написании запросов, когда задействованы NULL. Вы должны знать/знакомы с спецификацией ANSI NULL и связанным с ней поведением.

+0

Это может быть яснее, если вы сделали это как 'SET @testValue = (SELECT ...)'. – ErikE

+0

Понял и согласен, но я хочу показать, что одного только подзапроса достаточно, чтобы получить желаемый эффект, поскольку это может дать некоторое представление о том, почему движок ведет себя так, как он делает. – mikey

+0

Я думаю, что SET делает именно это. Все дело в различии между наборами строк и значениями (и выражениями). SELECT предназначен для наборов строк. В запросе, назначающем переменную, никакие строки не означают назначение. Но когда SELECT перегружен, чтобы назначить * значение *, то «no rows AS value» равно NULL. Это скобки, которые работают с магией. Попробуйте скобки с двумя столбцами или с запросом, который возвращает более 1 строки ... – ErikE

0

Это поведение по умолчанию SELECT.

При присвоении значения переменной с использованием SELECT, если нет значения, возвращаемого значения, SELECT не будет выполнять присвоение вообще, поэтому значение переменной не будет изменено.

С другой стороны, SET присваивает переменной NULL, если нет возвращаемого значения.

For more info

0

NULL является идеальным значение, которое вы хотели бы, но SQL двигатель не достаточно умен, потому что некоторые еще может понадобиться пустая строка, «» в той ситуации, или 0 или 1, вы видите. Поэтому ни одно значение по умолчанию не задано. Best установлен для вашего собственного значения по умолчанию. Вы можете увидеть ниже

DECLARE @testValue NVARCHAR(50) = 'TEST'; 

SELECT @testValue = 'NOTUSED' WHERE 2 > 1; 

IF 2 <> 1 
    SELECT @testValue = NULL; 

SELECT @testValue; -- Outputs 'TEST' 
SELECT @testValue = 'USED' WHERE 1 > 2; 
SELECT @testValue; -- Outputs 'USED' 
0

NULL в SQL используется для обозначения отсутствующих данных или неизвестное значение. В этом случае данные отсутствуют, значение @testValue известно, оно просто терпит неудачу при условии назначения, поэтому оно не получает нового значения.

Если вы должны были изменить первоначальное назначение, чтобы быть, как это

declare @testValue nvarchar(50) 

Вы получите NULL, как показано ниже:

select @testValue = 'NOTUSED' where 1 > 2; 
select @testValue; -- Outputs NULL 
select @testValue = 'USED' where 2 > 1; 
select @testValue; -- Outputs 'USED' 

Не слишком разочарованы вы не получаете NULL обратно в ваш пример. NULL не прост в обращении.

Например, вы не можете сравнить два значения NULL, поскольку экземпляры NULL не равны. Следовательно, вам также необходимо использовать специальные операторы, такие как ISNULL, чтобы проверить его.

В целом, на мой взгляд, следует избегать NULL как программирования. Это немного разногласия по всем языкам программирования. Но consjier это, даже создатель null Tony Hoare, называет создание нулевой его «миллиардной ошибки доллара».

Смежные вопросы