TSQL不会导致无限循环

时间:2014-10-06 13:33:36

标签: sql sql-server tsql

请参阅以下代码:

declare @crimeurn varchar(20)
DECLARE @finalresults TABLE (crime_urn varchar(20))
DECLARE @potentialresults TABLE (crime_urn varchar(20))

insert into @finalresults values ('1')    

DECLARE finalresults_cursor CURSOR FOR
SELECT crime_urn FROM @finalresults
OPEN finalresults_cursor 
FETCH NEXT FROM finalresults_cursor INTO @crimeurn

WHILE @@FETCH_STATUS = 0 
BEGIN 
    print @crimeurn  

    INSERT INTO @finalresults
    values ('2')

    FETCH NEXT FROM finalresults_cursor INTO @crimeurn
END 

select * from @finalresults --line 16

CLOSE finalresults_cursor 
DEALLOCATE finalresults_cursor 

第16行在SQL工作室管理器中显示5137或12,342行(随机变化)。我期望TSQL导致无限循环,因为在游标的每次迭代中都会插入表变量。

为什么它不会导致无限循环?即为什么返回5,137或12,342行。

3 个答案:

答案 0 :(得分:3)

您正在插入堆中。

堆是无序的。没有特别保证在当前行之后插入行并在下一次获取时拾取。

我对您的测试框架稍作修改,并添加了IDENTITY列。在我的情况下,在终止之前它排到了592,353行。

正如您从下面的结果中看到的那样,最后一行恰好被插入文件的前一页(从1623跳到184),因此从倒数第二行开始的分配有序扫描无法找到它。

enter image description here

重现的代码。

declare @crimeurn varchar(20)
DECLARE @finalresults TABLE (crime_urn varchar(20), ID int identity)
DECLARE @potentialresults TABLE (crime_urn varchar(20))

insert into @finalresults values ('1')    

DECLARE finalresults_cursor CURSOR FOR
SELECT crime_urn FROM @finalresults
OPEN finalresults_cursor 
FETCH NEXT FROM finalresults_cursor INTO @crimeurn

WHILE @@FETCH_STATUS = 0 
BEGIN 
    print @crimeurn  

    INSERT INTO @finalresults
    --OUTPUT INSERTED.ID
    values ('2')

    FETCH NEXT FROM finalresults_cursor INTO @crimeurn
END 

select *, sys.fn_PhysLocFormatter(%%physloc%%) from @finalresults --line 16
ORDER BY ID

CLOSE finalresults_cursor 
DEALLOCATE finalresults_cursor 

答案 1 :(得分:0)

编辑:下面的信息是错误的,但我已经离开了,因为我认为这是所谓的工作方式。

默认情况下,游标不会以INSENSITIVESTATIC模式运行。默认情况下,游标为DYNAMICOPTIMISTIC。游标上的documentation没有提到动态游标相对于INSERTS的行为方式。 INSERT行为似乎没有记录。

您可以使用SCROLL_LOCKS选项解决此问题,这样可以保证订单保存。


因为运行

时光标的定义是固定的
DECLARE finalresults_cursor CURSOR FOR
SELECT crime_urn FROM @finalresults

在那之后它是静止的。更新表变量@finalresults不会更改游标finalresults_cursor

就是这样:

X = 10
Y = X
X = 20
PRINT X, Y

输出:

20        10

答案 2 :(得分:0)

但是,如果你不关心或不知道光标的类型,你可以使用循环内的@@CURSOR_ROWS做一些"光标"逻辑:)。 Here是关于@@CURSOR_ROWS变量可能具有的值的一些文档,具体取决于游标的类型:。