web-dev-qa-db-ja.com

ストアドプロシージャの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_ _

代わりに、以下のように出力されました:

値_10_

値_10_

値_8_

値_8_

値_6_

値_6_

値_4_

値_4_

値_2_

値_2_

Whileブロック内で変数を宣言すると、反復ごとに値がNULLまたはデフォルト値(c#バックグラウンドから)にリセットされると思いました。

これが仕様による場合、私の質問は、SQLServerがブロック内のその変数の 'DECLARE'ステートメントをどのように処理するかです。変数はすでにメモリにあるので無視しますか?

誰かがこの動作を説明してくれませんか?

28
JPReddy

変数スコープは、この場合はストアドプロシージャのバッチ全体です。

ループごとに再宣言されるわけではありません

これは予想通りです

編集:

最近の ブログ記事 は非常によく似ています。著者はすぐに修正されました:-)

34
gbn

From Transact-SQL変数

変数のスコープは、変数を参照できるTransact-SQLステートメントの範囲です。変数のスコープは、変数が宣言された時点から、それが宣言されているバッチまたはストアドプロシージャの最後まで続きます。

DECLARE自体は実行可能なステートメントではありません。変数宣言はすべて コンパイル時に識別 であり、実行コンテキストでそれらのために予約されているメモリです。

2008+ Declare and 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
16
Martin Smith

これをお楽しみください

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
12
Mikael Eriksson

から 宣言

ローカル変数のスコープは、それが宣言されているバッチです。

T-SQLには「ローカル」スコープルールはありません。また、IFおよびELSEブロック内で同じ変数名を宣言することはできません。

Declareが行うのは、変数をdeclareすることだけです。 assignmentとは関係ありません。割り当てられたことのない変数の値はNULLです。しかし、その後、変数の値が再びNULLになる唯一の方法は、明示的な割り当てによるものです。

したがって、各ループ反復の先頭でNULLにする必要がある場合は、明示的に割り当てる必要があります。

T-SQLではWHILE..ENDのスコープは個別ではありません。たとえば、SELECT @insidevalueWHILEENDの後。

3
Alex K.
 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
1
arun sai

多くの場合、整数データ型にはNULLの0しかありません

宣言文はループ内で毎回発生するわけではありません

なぜ使用しないのですか

DECLARE @loopcounter INT
SET @loopcounter=10
WHILE @loopcounter > 0
BEGIN
  IF @loopcounter%2 = 0
  PRINT 'Value_' + CAST(@loopcounter AS NVARCHAR) + '_'
  else
  PRINT 'Value_ _'
  SET @loopcounter = @loopcounter - 1
END

それは与える:

Value_10_
Value_ _
Value_8_
Value_ _
Value_6_
Value_ _
Value_4_
Value_ _
Value_2_
Value_ _
0
mcelroyd
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
0
user2798124