事象
ループ、またはカーソル内で、毎回変数をnull
で初期化したい時、DECLARE
による宣言のみだと初期化されない。
原因
- ループ、カーソルで宣言済み変数名を宣言してエラーにならず、アドレスが更新されない。
- 代入処理がなければ値は変更されない。
って仕様があるのだと思う。多分。ドキュメントが見つからなかった。
結論
-
DECLARE
で初期化する場合、代入をする。 - または、ループ内の
DECLARE
を避け、ループの外でDECLARE
してループ内はSET
で初期化する。
調査
初期化できるパターン1
BEGIN
DECLARE @count INT = 0
WHILE @count < 2
BEGIN
SET @count = @count + 1
DECLARE @id INT = null -- ここ
PRINT '代入前: null?'
PRINT CONVERT(NVARCHAR(10), @id)
SET @id = 1;
PRINT '代入後: 1?'
PRINT CONVERT(NVARCHAR(10), @id)
END
END
GO
-- 結果
[2020-03-03 11:06:41] [S0001] 代入前: null?
[2020-03-03 11:06:41] [S0001]
[2020-03-03 11:06:41] [S0001] 代入後: 1?
[2020-03-03 11:06:41] [S0001] 1
[2020-03-03 11:06:41] [S0001] 代入前: null?
[2020-03-03 11:06:41] [S0001]
[2020-03-03 11:06:41] [S0001] 代入後: 1?
[2020-03-03 11:06:41] [S0001] 1
初期化できるパターン2
BEGIN
DECLARE @count INT = 0
WHILE @count < 2
BEGIN
SET @count = @count + 1
DECLARE @id INT = 2 -- ここ
PRINT '代入前: 2?'
PRINT CONVERT(NVARCHAR(10), @id)
SET @id = 1;
PRINT '代入後: 1?'
PRINT CONVERT(NVARCHAR(10), @id)
END
END
GO
-- 結果
[2020-03-03 11:10:45] [S0001] 代入前: 2?
[2020-03-03 11:10:45] [S0001] 2
[2020-03-03 11:10:45] [S0001] 代入後: 1?
[2020-03-03 11:10:45] [S0001] 1
[2020-03-03 11:10:45] [S0001] 代入前: 2?
[2020-03-03 11:10:45] [S0001] 2
[2020-03-03 11:10:45] [S0001] 代入後: 1?
[2020-03-03 11:10:45] [S0001] 1
初期化できないパターン
BEGIN
DECLARE @count INT = 0
WHILE @count < 2
BEGIN
SET @count = @count + 1
DECLARE @id INT -- ここ
PRINT '代入前: null?'
PRINT CONVERT(NVARCHAR(10), @id)
SET @id = 1;
PRINT '代入後: 1?'
PRINT CONVERT(NVARCHAR(10), @id)
END
END
GO
-- 結果
[2020-03-03 11:09:56] [S0001] 代入前: null?
[2020-03-03 11:09:56] [S0001]
[2020-03-03 11:09:56] [S0001] 代入後: 1?
[2020-03-03 11:09:56] [S0001] 1
[2020-03-03 11:09:56] [S0001] 代入前: null?
[2020-03-03 11:09:56] [S0001] 1
[2020-03-03 11:09:56] [S0001] 代入後: 1?
[2020-03-03 11:09:56] [S0001] 1