Код, размещенный здесь, является примером кода, это не рабочий код. Я сделал это, чтобы объяснить проблему, которую я объясняю, читабельной / краткой.
Используя код, подобный приведенному ниже, мы сталкиваемся со странной ошибкой. После каждой вставки цикл WHILE останавливается.
таблица содержит 100 строк, когда вставка выполняется после 50 строк, курсор останавливается, коснувшись только первых 50 строк. Когда вставка выполняется после 55, она останавливается после 55 и т. Д.
-- This code is an hypothetical example written to express
-- an problem seen in production
DECLARE @v1 int
DECLARE @v2 int
DECLARE MyCursor CURSOR FAST_FORWARD FOR
SELECT Col1, Col2
FROM table
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO @v1, @v2
WHILE(@@FETCH_STATUS=0)
BEGIN
IF(@v1>10)
BEGIN
INSERT INTO table2(col1) VALUES (@v2)
END
FETCH NEXT FROM MyCursor INTO @v1, @v2
END
CLOSE MyCursor
DEALLOCATE MyCursor
Существует триггер AFTER INSERT на table2 , который используется для регистрации мутаций на table2 в третьей таблице с метким именем mutations Он содержит курсор, который вставляет для обработки вставки (мутации записываются для каждого столбца очень специфическим способом, для которого требуется курсор).
Немного предыстории: это существует на множестве небольших таблиц поддержки. Для проекта требуется, чтобы каждое изменение, внесенное в исходные данные, регистрировалось для целей аудита. Таблицы с регистрацией содержат такие вещи, как номера банковских счетов, на которые будут зачисляться огромные суммы денег. Существует максимум несколько тысяч записей, и они должны изменяться очень редко. Функция аудита предназначена для предотвращения мошенничества: мы записываем «что изменилось» с «кто это сделал».
Очевидный, быстрый и логичный способ реализовать это - хранить всю строку при каждом обновлении. Тогда нам не понадобится курсор, и он будет работать лучше. Однако политика ситуации означает, что мои руки связаны.
Уф. Теперь вернемся к вопросу.
Упрощенная версия триггера (реальная версия выполняет вставку в столбец, а также вставляет старое значение):
--This cursor is an hypothetical cursor written to express
--an problem seen in production.
--On UPDATE a new record must be added to table Mutaties for
--every row in every column in the database. This is required
--for auditing purposes.
--An set-based approach which stores the previous state of the row
--is expressly forbidden by the customer
DECLARE @col1 int
DECLARE @col2 int
DECLARE @col1_old int
DECLARE @col2_old int
--Loop through old values next to new values
DECLARE MyTriggerCursor CURSOR FAST_FORWARD FOR
SELECT i.col1, i.col2, d.col1 as col1_old, d.col2 as col2_old
FROM Inserted i
INNER JOIN Deleted d ON i.id=d.id
OPEN MyTriggerCursor
FETCH NEXT FROM MyTriggerCursor INTO @col1, @col2, @col1_old, @col2_old
--Loop through all rows which were updated
WHILE(@@FETCH_STATUS=0)
BEGIN
--In production code a few more details are logged, such as userid, times etc etc
--First column
INSERT Mutaties (tablename, columnname, newvalue, oldvalue)
VALUES ('table2', 'col1', @col1, @col1_old)
--Second column
INSERT Mutaties (tablename, columnname, newvalue, oldvalue)
VALUES ('table2', 'col2', @col2, @col1_old)
FETCH NEXT FROM MyTriggerCursor INTO @col1, @col2, @col1_old, @col2_old
END
CLOSE MyTriggerCursor
DEALLOCATE MyTriggerCursor
Почему код выходит из середины цикла?