CURSOR中的SQL WITH关键字

时间:2014-09-24 05:09:02

标签: sql sql-server

在CURSOR中使用WITH关键字时观察到一些奇怪的行为:

WITH minuteList (aMinute) AS
    (
        SELECT @startTime UNION ALL
        SELECT DATEADD(MINUTE, 1, aMinute)
        FROM minuteList
        WHERE aMinute < DATEADD(MINUTE, 9, @startTime)
    )
SELECT * FROM minuteList

上面的代码可以很好地创建一个包含一个aMinute列的表和一个间隔为1分钟的10个日期时间行。但是,下面的代码进入无限循环,只能无限地打印@startTime值。

DECLARE cursor1 CURSOR FOR
    WITH minuteList (aMinute) AS
    (
        SELECT @startTime UNION ALL
        SELECT DATEADD(MINUTE, 1, aMinute)
        FROM minuteList
        WHERE aMinute < DATEADD(MINUTE, 9, @startTime)
    )
    SELECT * FROM minuteList
OPEN cursor1
FETCH NEXT FROM cursor1 INTO @laterTime
WHILE @@FETCH_STATUS = 0 BEGIN
    PRINT @laterTime
END
CLOSE cursor1;
DEALLOCATE cursor1;

有人可以解释发生了什么以及无限循环发生的原因吗?

1 个答案:

答案 0 :(得分:0)

我对游标调用进行了逐行分析,以解释它为什么会进入无限循环。

OPEN cursor1                             // Opens your cursor
FETCH NEXT FROM cursor1 INTO @laterTime  // Takes the first row returned by the
                                            cursor and inserts it into the 
                                            variable @laterTime
WHILE @@FETCH_STATUS = 0 BEGIN           // Checks if the next value has been
                                            fetched and executes
                                            the code inside the loop
PRINT @laterTime                         // Prints the current row
END                                      // Ends the loop when FETCH_STATUS is 
                                            not 0 (when fetch fails).
CLOSE cursor1;                           // Closes the cursor.

无限循环的原因是@@ FETCH_STATUS永远不会被更改,因为您只访问了游标的第一行(获取没有失败,因为它没有被多次调用)。打印@laterTime后,需要获取循环内光标的下一个值。只有当提取失败时,循环才会终止。

this example视为参考。

修改后的代码如下所示:

OPEN cursor1
FETCH NEXT FROM cursor1 INTO @laterTime
WHILE @@FETCH_STATUS = 0 BEGIN
    PRINT @laterTime
    FETCH NEXT FROM cursor1 INTO @laterTime
END
CLOSE cursor1;