我在存儲過程中觀察到一個奇怪的事物,在表變量上進行選擇。它總是返回在遊標的第一次迭代中獲取的值(在後續迭代中)。以下是一些證明這一點的示例代碼。遊標內部的表變量,奇怪的行爲 - SQL Server
DECLARE @id AS INT;
DECLARE @outid AS INT;
DECLARE sub_cursor CURSOR FAST_FORWARD
FOR SELECT [TestColumn]
FROM testtable1;
OPEN sub_cursor;
FETCH NEXT FROM sub_cursor INTO @id;
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @Log TABLE (LogId BIGINT NOT NULL);
PRINT 'id: ' + CONVERT (VARCHAR (10), @id);
INSERT INTO Testtable2 (TestColumn)
OUTPUT inserted.[TestColumn] INTO @Log
VALUES (@id);
IF @@ERROR = 0
BEGIN
SELECT TOP 1 @outid = LogId
FROM @Log;
PRINT 'Outid: ' + CONVERT (VARCHAR (10), @outid);
INSERT INTO [dbo].[TestTable3] ([TestColumn])
VALUES (@outid);
END
FETCH NEXT FROM sub_cursor INTO @id;
END
CLOSE sub_cursor;
DEALLOCATE sub_cursor;
然而,雖然我被張貼在SO的代碼,並試圖各種組合,我觀察到去除從下面的線頂部,給我的右值超出表變量的一個光標的內部。
SELECT TOP 1 @outid = LogId FROM @Log;
這將使它像這樣
SELECT @outid = LogId FROM @Log;
我不知道這裏發生了什麼。我認爲表格變量的TOP 1應該工作,認爲在循環的每次迭代中都會創建一個新表格。有人可以在表變量範圍和壽命期間拋出光明。
更新:我有解決方案來繞過這裏的奇怪行爲。 作爲一種解決方案,我已經在循環前面的頂部聲明瞭該表並刪除了循環開始處的所有行。
如果我正確地讀取了這段代碼,您可以在每個循環中創建一個新的@Log表。如果是這樣的話@Log總是隻有一個記錄!?你想要達到的目標是什麼,你期望什麼,真正發生了什麼。到目前爲止,我需要更多的澄清來提供幫助。 – YvesR
@YvesR - 您沒有正確閱讀。它是一個聲明語句,不是可執行的行。它被隱式創建一次。代碼甚至不必到達那條線。例如'IF(1 = 0)開始聲明@T TABLE(X INT)END; SELECT * FROM @T;'(儘管解析器在它看到聲明之前遇到引用時會報錯) –
@MartinSmith,你是對的。感謝您的解釋。 –