Как совершить внутри цикла CURSOR? - PullRequest
2 голосов
/ 21 мая 2010

Я пытаюсь выяснить, возможно ли выполнить обновление в цикле курсора, и эти обновленные данные отражаются во время второй итерации в цикле.

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 будет пустым для всех записей. В приведенном выше sql я делаю выбор внутри цикла курсора, чтобы запросить MyTable, где значением события является «Нет события», но запрос не возвращает значения, даже если я делаю обновление в следующей строке. Итак, я думаю, возможно ли вообще обновить таблицу, и обновленные данные будут отражены в следующей итерации цикла курсора.

Спасибо за любую помощь, Джавид

Ответы [ 2 ]

4 голосов
/ 21 мая 2010

Во-первых, вам не нужен курсор. Нечто подобное следующему будет иметь ту же семантику (из начальной позиции, где все 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 голосов
/ 21 мая 2010

Даже если бы это работало, это не гарантировало бы правильного результата, так как вы пропустили предложение ORDER BY в своем запросе.

В зависимости от этого все записи, никакие записи или произвольное подмножество записей моглиобновлено.

Не могли бы вы объяснить простым языком, что должна делать ваша хранимая процедура?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...