2010-05-21 91 views
2

我想看看它是否有可能在遊標循環中執行更新,並且在循環的第二次迭代期間反映此更新的數據。如何在CURSOR循環內部提交?

DECLARE cur CURSOR 
FOR SELECT [Product], [Customer], [Date], [Event] FROM MyTable 
WHERE [Event] IS NULL 

OPEN cur 
FETCH NEXT INTO @Product, @Customer, @Date, @Event 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    SELECT * FROM MyTable WHERE [Event] = 'No Event' AND [Date] < @DATE 
    -- Now I update my Event value to 'No Event' for records whose date is less than @Date 
    UPDATE MyTable SET [Event] = 'No Event' WHERE [Product] = @Product AND [Customer] = @Customer AND [Date] < @DATE 
    FETCH NEXT INTO @Product, @Customer, @Date, @Event 
END 
CLOSE cur 
DEALLOCATE cur 

假設當SQL執行事件列爲空的所有記錄 在上面的SQL,我做遊標循環內選擇查詢MyTable的地方事件的值是「無事件」,但查詢返回即使我正在更新下一行,也沒有任何價值。 所以,我想如果甚至有可能更新一個表,更新的數據會反映在下一次迭代的遊標循環中。

感謝您的幫助, Javid

回答

0

即使這個工作,因爲你錯過了在查詢的ORDER BY條款,這將不能保證正確的結果。

根據這一點,可以更新所有記錄,無記錄或記錄的任何隨機子集。

你能否用簡單的英文說明你的存儲過程應該做什麼?

+0

嗨, 以前記錄的原因,我不得不使用光標我將不得不計算基於事件列值的每個記錄均線(即無事件)。計算移動平均數以確定某些異常,並使用它將事件值設置爲「異常」。但是,如果我發現連續三次或更多次「異常」,我需要將它們全部重置爲「無事件」,因此,當計算下一個記錄的平均值時,需要使用以前的數據點。對不起,如果我讓你困惑。希望這些信息可以幫助.. – user320587 2010-05-21 17:58:40

+1

@user:你可以請發佈一個示例記錄集和所需的輸出嗎? – Quassnoi 2010-05-21 18:03:27

+0

最終的結果將是確定性的,它只是不確定性如何實現。如果碰巧按日期從大到小的順序處理行,與按升序排列的操作相比,所需的操作要少得多。 – 2013-03-20 09:12:17

4

首先你不應該在這裏需要一個遊標。類似以下內容的語義相同(從所有Event均爲NULL的起始位置開始)並且效率更高。

WITH T 
    AS (SELECT [Event], 
       RANK() OVER (PARTITION BY [Product], [Customer] 
           ORDER BY [Date] DESC) AS Rnk 
     FROM MyTable) 
UPDATE T 
SET [Event] = 'No Event' 
WHERE Rnk > 1 

其次關於在遊標循環中提交的標題問題與其他任何地方相同。你只需要一個COMMIT聲明。但是,如果您不在較大的事務中運行此語句,則UPDATE語句將自動提交。

第三您真正的問題似乎並不是關於提交。它關於遊標反映了隨後迭代中數據的更新。對於這個問題的情況下,你需要一個DYNAMIC光標

定義體現在其 結果中的行,你的光標周圍滾動設置所做的所有數據更改的光標。數據值, 順序以及行的成員資格可以在每次獲取時更改。

並非所有的查詢都支持動態遊標。在問題中的代碼會但沒有ORDER BY它是不確定的行將被處理的順序,因此是否會看到可見的結果。我添加了一個ORDER BY和一個索引來支持這個功能,以允許使用動態遊標。

如果您嘗試以下操作,將會看到遊標僅獲取一行,因爲日期按降序處理,並且在處理第一行時更新表,以便不再有行符合下一次獲取的條件。如果在遊標循環中註釋掉UPDATE,則所有三行均被提取。

CREATE TABLE MyTable 
    (
    [Product] INT, 
    [Customer] INT, 
    [Date]  DATETIME, 
    [Event] VARCHAR(10) NULL, 
    PRIMARY KEY ([Date], [Product], [Customer]) 
) 


INSERT INTO MyTable 
VALUES (1,1,'20081201',NULL), 
     (1,1,'20081202',NULL), 
     (1,1,'20081203',NULL) 

DECLARE @Product INT, 
     @Customer INT, 
     @Date  DATETIME, 
     @Event VARCHAR(10) 

DECLARE cur CURSOR DYNAMIC TYPE_WARNING FOR 
    SELECT [Product], 
     [Customer], 
     [Date], 
     [Event] 
    FROM MyTable 
    WHERE [Event] IS NULL 
    ORDER BY [Date] DESC 

OPEN cur 

FETCH NEXT FROM cur INTO @Product, @Customer, @Date, @Event 

WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SELECT @Product, 
      @Customer, 
      @Date, 
      @Event 

     -- Now I update my Event value to 'No Event' for records whose date is less than @Date 
     UPDATE MyTable 
     SET [Event] = 'No Event' 
     WHERE [Product] = @Product 
      AND [Customer] = @Customer 
      AND [Date] < @Date 

     FETCH NEXT FROM cur INTO @Product, @Customer, @Date, @Event 
    END 

CLOSE cur 

DEALLOCATE cur 

DROP TABLE MyTable 
+0

這不能回答這個問題。 – dansan 2013-03-19 19:23:49

+0

@丹桑 - 你說得對。糾正。 – 2013-03-20 09:01:02

+0

即使它沒有回答這個問題,我對這個答案的學習方式比我對短的直接答案更多......馬丁! – jambriz 2014-09-30 17:54:23