2014-09-24 46 views
1

關鍵字SQL WITH關鍵字使用內部CURSOR當觀察一些奇怪的行爲:WITH內部CURSOR

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

上面的代碼工作完全創建表,帶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

到底爲什麼你要堅持到**光標這種**?避免像瘟疫一樣的遊標! – 2014-09-24 05:11:15

+0

@Matthew Haugen不,配對,這給附近DECLARE cursor1 – Alxg 2014-09-24 05:18:11

+1

'WHILE @@ FETCH_STATUS = 0'附近的語法不正確。 FETCH_STATUS從不被操縱,所以它什麼時候從0改變到終止循環? – CodeNewbie 2014-09-24 05:21:55

回答

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;