如何在CURSOR循环中提交?

时间:2010-05-21 17:39:26

标签: sql-server 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执行时,所有记录的Event列都为NULL 在上面的sql中,我在游标循环内部进行选择以查询MyTable,其中Event值为“No Event”,但即使我在下一行中进行更新,查询也不返回任何值。 所以,我在想是否有可能更新一个表,更新的数据会反映在游标循环的下一次迭代中。

感谢您的帮助, Javid

2 个答案:

答案 0 :(得分:4)

首先,你不需要光标。类似下面的内容将具有相同的语义(从所有EventNULL的起始位置)并且效率更高。

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 

答案 1 :(得分:0)

即使这样做有效,但由于您错过了查询中的ORDER BY子句,因此无法保证正确的结果。

根据这一点,可以更新所有记录,无记录或任何随机记录子集。

请您用简单的英语解释一下您的存储过程应该做什么?