Подтвердить что ты не робот

Область переменных, которые определены в блоке while в хранимых процедурах - SQl Server

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

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 _

значение_2 _

значение_2 _

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

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

Может кто-нибудь, пожалуйста, объясните мне это поведение? Пожалуйста, со мной, если ты обнаружишь, что это глупо. Я все еще участвую:)

Обновление: Спасибо всем за примеры и объяснения. Сегодня вы заставили меня узнать новое.

4b9b3361

Ответ 1

Область переменной - это целая партия в этом случае хранимая процедура.

Он не повторно объявляется в каждом цикле

Итак, это точно так, как ожидалось

Изменить:

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

Ответ 2

От Переменные Transact-SQL

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

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

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

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

Ответ 3

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

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

Ответ 4

От Объявить:

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

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

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

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

Ответ 5

В T-SQL a WHILE..END не является индивидуально областью, вы можете, например, SELECT @insidevalue после WHILE END.

Ответ 6

DECLARE @loopcounter INT
SET @loopcounter=10

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

    set @[email protected]
    PRINT 'Value_' + CAST(@insidevalue AS NVARCHAR) + '_'
  end
  ELSE

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

Ответ 7

 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