Область переменных, которые определены в блоке while в хранимых процедурах - SQl Server - PullRequest
26 голосов
/ 18 мая 2011

Я столкнулся с интересным сценарием (по крайней мере для меня) в хранимой процедуре. Хотели бы иметь мнение экспертов и мысли по этому поводу.

DECLARE @loopcounter INT
SET @loopcounter=10

WHILE @loopcounter > 0
BEGIN
  DECLARE @insidevalue int

  IF (@loopcounter%2 = 0)
  SET @insidevalue = @loopcounter

  PRINT 'Value_' + CAST(@insidevalue AS NVARCHAR) + '_'

  SET @loopcounter = @loopcounter - 1
END

Я ожидал, что этот блок выдаст вывод, как показано ниже

Value_10_

Value_ _

Value_8_

Value_ _

Value_6_

Value_ _

Value_4_

Value_ _

Value_2_

Value_ _

Вместо этого я получил вывод, как показано ниже:

Value_10_

Value_10_

Value_8_

Value_8_

Value_6_

Value_6_

Value_4_

Value_4_

Value_2_

Value_2_

Я думал, что если я объявлю переменную внутри блока while, то для каждой итерации он будет сбрасывать значение в NULL или значение по умолчанию (из c # background).

Если это умышленно, то мой вопрос заключается в том, как SQLServer обрабатывает оператор DECLARE для этой переменной внутри блока while? Это игнорирует это, поскольку переменная уже находится в памяти?

Может кто-нибудь объяснить мне такое поведение?

Ответы [ 7 ]

34 голосов
/ 18 мая 2011

Переменная scope - это целая партия, в данном случае хранимая процедура.

Не повторяется каждый цикл

Так что это в точности как ожидалось

Редактировать:

Недавно появилась статья в блоге , которая очень похожа. Автор был быстро исправлен: -)

16 голосов
/ 18 мая 2011

С Переменные Transact-SQL

Область действия переменной - это диапазон операторов Transact-SQL, которые может ссылаться на переменную. Объем переменной длится от указать, что он объявлен до конца пакета или хранимой процедуры в который объявлен.

DECLARE сам по себе не является исполняемым оператором. Все объявления переменных идентифицируются во время компиляции , и память зарезервирована для них в контексте выполнения.

Если вы используете синтаксис 2008+ Declare и Set. Однако часть Set оператора будет выполняться при каждой итерации цикла.

DECLARE @loopcounter INT
SET @loopcounter=10

WHILE @loopcounter > 0
BEGIN
  DECLARE @insidevalue INT = NULL

  IF (@loopcounter%2 = 0)
  SET @insidevalue = @loopcounter

  PRINT 'Value_' + CAST(@insidevalue AS NVARCHAR) + '_'

  SET @loopcounter = @loopcounter - 1
END
12 голосов
/ 18 мая 2011

Попробуйте это для удовольствия

if 1 = 0
begin
  -- will never happen
  declare @xx int
end  
else  
begin
  set @xx = 1
end  
print @xx

Очевидно, код объявления не должен выполняться. Объявляться только перед использованием.

Это не работает

if 1 = 0
begin
  -- will never happen
  set @xx = 1
end  
else  
begin
  declare @xx int
end  
print @xx
6 голосов
/ 18 мая 2011

С Объявить :

Область действия локальной переменной - это пакет, в котором она объявлена.

Больше нет "Локальные »правила видимости в T-SQL.Это также означает, что вы не можете объявить одно и то же имя переменной внутри блоков IF и ELSE.

Все, что объявить, - это , объявляет переменную.Это не имеет отношения к присваиванию .Значение любой переменной, которой никогда не присваивалось, равно NULL.Но после этого единственным способом, которым значение переменных снова станет NULL, является явное присваивание.

Если вам нужно, чтобы оно было NULL в верхней части каждой итерации цикла, следовательно, вы должны явно назначитьэто.

3 голосов
/ 18 мая 2011

В T-SQL WHILE..END не имеет отдельной области, например, SELECT @insidevalue после WHILE END.

1 голос
/ 08 января 2016
 DECLARE @loopcounter INT
 DECLARE @insidevalue int
   SET @loopcounter=10
       WHILE @loopcounter > 0
        BEGIN
          IF (@loopcounter%2 = 0)
          BEGIN
          SET @insidevalue = @loopcounter
          PRINT 'Value_' + CAST(@insidevalue AS NVARCHAR) + '_'
          END
    ELSE
      PRINT 'Value_'+' '+'_'
      SET @loopcounter = @loopcounter - 1
   END
0 голосов
/ 20 сентября 2013
DECLARE @loopcounter INT
SET @loopcounter=10

WHILE @loopcounter > 0
BEGIN
  DECLARE @insidevalue int
  IF (@loopcounter%2 = 0)
  begin

    set @insidevalue=@loopcounter
    PRINT 'Value_' + CAST(@insidevalue AS NVARCHAR) + '_'
  end
  ELSE

    PRINT 'Value_' + ' ' + '_'
    SET @loopcounter = @loopcounter - 1
END
...