2014-01-27 6 views
0

Когда запись обновляется, запускается триггер, где он назначает новую запись, важный сгенерированный номер (через хранимую процедуру).Trigger Multiple Updates

Он отлично работает.

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

Как я могу выполнить цикл или sql-инструкцию, чтобы применить рассчитанное значение к каждой строке INSERTED (обновлено).

SELECT @id = id FROM INSERTED -- Could contain multiple rows, but (wrongly) only applies to one 

IF (@id IS NOT NULL) 
BEGIN 
    DECLARE @No bigint 
    EXEC assignNo @No = @No OUTPUT 

    UPDATE myTable SET No = @No 
    WHERE id = @id 
END 
+0

Вы пытаетесь поместить то же значение @No во все обновленные строки или отдельное значение для каждой строки? –

+0

Можно ли изменить функцию proc на функцию? –

+0

@JoachimIsaksson Отдельное значение за строку. Что касается идеи функции, я буду исследовать ее. – Doomsknight

ответ

4

Вот что я пытался с моей линией допроса. Если у вашего центрального генератора IDENTITY есть дополнительный бесполезный столбец, это может избежать вставки строк с DEFAULT VALUES, что равно difficult, cumbersome and downright unintuitive to do with more than one row (и, возможно, невозможно, скажем, в SQL Server 2005). Так, изображая эту таблицу генератора выглядит следующим образом:

CREATE TABLE dbo.OtherTable(OtherTableID INT IDENTITY(1,1), UselessColumn BIT); 

И реальный стол вы вставка в выглядит следующим образом:

CREATE TABLE dbo.MyTable(ID INT IDENTITY(1,1), [No] INT, foo VARCHAR(32)); 

Мы можем создать INSTEAD OF INSERT триггер, который вставляет несколько строк в dbo.OtherTable, захватывает набор из IDENTITY значений, сгенерированных, затем в конечном итоге вставляет эти значения вместе с реальными данными, назначая каждое сгенерированное значение в одну строку произвольно.

CREATE TRIGGER dbo.trMyTable 
ON dbo.MyTable 
INSTEAD OF INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @newIDs TABLE(ID INT IDENTITY(1,1), [No] INT); 

    INSERT dbo.OtherTable(UselessColumn) 
    OUTPUT inserted.OtherTableID INTO @newIDs([No]) 
    SELECT NULL FROM inserted; 

    INSERT dbo.MyTable([No],foo) 
    SELECT n.[No], i.foo FROM @newIDs AS n 
    INNER JOIN 
    (
    SELECT *, rn = ROW_NUMBER() OVER (ORDER BY foo) FROM inserted 
) AS i ON i.rn = n.ID; 
END 
GO 

Причина INSTEAD OF INSERT триггер лучше, потому что это позволяет избежать двойной работы (вставить кучу строк, а затем обновить их все). Очевидно, что у вас больше столбцов, чем foo; это просто упрощенная демонстрация.

Если вам также необходимо сделать что-то подобное для пакетных обновлений, вам придется обновить вопрос с большим количеством требований (и включить информацию, такую ​​как первичный ключ в целевой таблице).

+0

Это определенное решение моей проблемы. Хотя, как вы уже упоминали, мне нужно сделать это для обновления и удаления. Хотя я должен был понять это сейчас. Меня беспокоит, что если что-то пойдет не так, ничего не будет вставлено. (Хотя я думаю, что это никогда не пойдет не так). И INSERT требует ввода всех 30 имен полей. +1, спасибо. будет играть с ним. – Doomsknight

+0

@ Спасибо за ответ. В конце концов я сделал свое решение. Добавлено для вас, чтобы видеть. С уважением. – Doomsknight

0

Вот решение, за которое я пошел.

Я вставляю в свой otherTable, используя IDs в INSERTED для генерации чисел. Плюс я добавляю строку datetime, чтобы сделать ее более уникальной, так как поиск только id не уникален в этой таблице.

Я затем обновить myTable с помощью IDs из INSERTED и найти Макса No в otherTable с использованием уникального идентификатора id + datetime строку. Он присваивается правильной записи и работает в пакетных вставках/обновлениях.

DECLARE @datetime as varchar(126) 
SET @datetime = (SELECT CONVERT(VARCHAR, GETDATE(), 120)) 


INSERT INTO OtherTable  
SELECT I.id + ' ' + @datetime 
FROM INSERTED I 

UPDATE myTable  
SET 
    myTable.foo = 'U' , 
    myTable.No = (SELECT MAX(No) FROM OtherTable W WHERE W.Info = I.id+ ' ' + @datetime) 
FROM INSERTED I 
WHERE 
    myTable.id = I.id 
+0

Этот код должен находиться внутри какого-либо триггера? –

+0

На первый взгляд это не похоже, что это сработает, но нормально ... –

+0

@AaronBertrand Но это действительно работает! :) И да, внутри триггера. – Doomsknight