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