SQL Server Триггер для работы с несколькими вставками строк - PullRequest
10 голосов
/ 01 февраля 2010

Я поддерживаю некоторый код, который имеет триггер для таблицы для увеличения столбца.Этот столбец затем используется сторонним приложением A .Допустим, таблица называется test с двумя столбцами num1 и num2 .Триггер запускается при каждой вставке num1 в test .Ниже приведен триггер:

USE [db1]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[TEST_MYTRIG] ON [dbo].[test]
FOR INSERT AS
begin
SET NOCOUNT ON
DECLARE @PROC_NEWNUM1 VARCHAR (10)
DECLARE @NEWNUM2 numeric(20)

SELECT @PROC_NEWNUM1 = num1 FROM INSERTED
select @NEWNUM2 = MAX(num2) from TEST
if @NEWNUM2 is null
Begin
set  @NEWNUM2  = 0
end
set @NEWNUM2 = @NEWNUM2 + 1
UPDATE TEST SET num2 = @NEWNUM2 WHERE num1 = @PROC_NEWNUM1
SET NOCOUNT OFF
End

Это прекрасно работает при простых вставках на основе строк, но есть другое стороннее приложение B (вздох), которое иногда выполняет несколько вставок в эту таблицу, что-то вродеэто, но не совсем так:

INSERT INTO [db1].[dbo].[test]
           ([num1])

   Select db1.dbo.test.num1 from [db1].[dbo].[test]
GO

Это приводит к тому, что триггер работает некорректно ...

Теперь у меня нет доступа к источнику приложения A или B и управлять только базой данных и триггером.Есть ли что-нибудь, что можно сделать с помощью триггера, чтобы обновления, сделанные для num2 , были правильными в случае нескольких вставок?

Решение:

Ниже приводится решение, основанное на коде аффана:

 DECLARE @PROC_NEWNUM1 VARCHAR (10)
 DECLARE @NEWNUM2 numeric(20)
 DECLARE my_Cursor CURSOR FAST_FORWARD FOR SELECT num1 FROM INSERTED;

 OPEN my_Cursor 
 FETCH NEXT FROM my_Cursor into @PROC_NEWNUM1

 WHILE @@FETCH_STATUS = 0 
 BEGIN 

 select @NEWNUM2 = MAX(num2) from TEST
 if @NEWNUM2 is null
 Begin
    set  @NEWNUM2  = 0
 End
 set @NEWNUM2 = @NEWNUM2 + 1
 UPDATE TEST SET num2 = @NEWNUM2  WHERE num1 = @PROC_NEWNUM1
 FETCH NEXT FROM my_Cursor into @PROC_NEWNUM1  
 END

CLOSE my_Cursor
DEALLOCATE my_Cursor

Проверьте здесь подход на основе множеств: SQL Server - триггер перезаписи, чтобы избежать подхода на основе курсора

Ответы [ 4 ]

5 голосов
/ 02 февраля 2010

Вам просто нужно открыть курсор на INSERTED, итерировать его для @ PROC_NEWNUM1 и поместить остаток кода в этот цикл. * 1001 например *

 DECLARE @PROC_NEWNUM1 VARCHAR (10)
 DECLARE @NEWNUM2 numeric(20)
 DECLARE my_Cursor CURSOR FOR SELECT num1 FROM INSERTED; 
 OPEN my_Cursor; 

 FETCH NEXT FROM @PROC_NEWNUM1; 


 WHILE @@FETCH_STATUS = 0 
 BEGIN FETCH NEXT FROM my_Cursor 
 select @NEWNUM2 = MAX(num2) from TEST
 if @NEWNUM2 is null
 Begin
  set  @NEWNUM2  = 0
 end
 set @NEWNUM2 = @NEWNUM2 + 1
 UPDATE TEST SET num2 = @NEWNUM2 WHERE num1 = @PROC_NEWNUM1

 END; 

CLOSE my_Cursor; DEALLOCATE my_Cursor;
3 голосов
/ 01 февраля 2010

Взгляните на inserted псевдо-таблицу в вашем триггере, так как она будет содержать несколько строк во время этих операций В любом случае, вы всегда должны обрабатывать несколько строк в своих триггерах.

Смотрите здесь для получения дополнительной информации:

Как проверить наличие нескольких действий строки в триггере SQL Server?

2 голосов
/ 01 февраля 2010

Триггер должен быть переписан для обработки вставки нескольких строк. Никогда не пишите такой триггер, используя переменные. Все триггеры должны всегда учитывать, что когда-нибудь кто-то собирается сделать вставку / обновление / удаление в несколько строк.

Вы также не должны увеличивать столбцы в триггере, если вам нужны увеличенные номера столбцов, почему вы не используете столбец идентификаторов?

0 голосов
/ 07 марта 2017
INSERT INTO dbo.media_queue (table_name, table_id, media_id, tunnel, sub_tunnel, event)
        SELECT
            'media_info'
            ,i.id
            ,i.session_id
            ,i.tunnel
            ,i.sub_tunnel
            ,NULL
        FROM INSERTED i;
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...