SQL Server - переписать триггер, чтобы избежать подхода на основе курсора - PullRequest
4 голосов
/ 02 февраля 2010

Если у меня есть таблица Test с двумя столбцами num1 и num2 и следующим триггером, который просто увеличивает num2 при вставках num1:

 DECLARE @PROC_NEWNUM1 VARCHAR (10)
 DECLARE @NEWNUM2 numeric(20)
 DECLARE my_Cursor CURSOR 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 Триггер для работы с несколькими вставками строк )

Решение без временной таблицы с использованием Row_Number (только начиная с Sql 2005):

SELECT @MAXNUM2 = MAX(num2) FROM TEST
if @MAXNUM2 IS NULL
BEGIN
    SET @MAXNUM2=0
END

UPDATE TEST
SET num2 = @MAXNUM2 + SubQuery.R
FROM
(
SELECT num1, ROW_NUMBER() OVER (ORDER BY num1) as R FROM inserted
)
SubQuery
INNER JOIN TEST on SubQuery.num1 =  TEST.num1

Ответы [ 3 ]

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

Если я правильно понимаю, нормальное обновление даст вам то, что вы хотите.

UPDATE  TEST
SET     num2 = @NEWNUM2
FROM    TEST t
        INNER JOIN Inserted i ON i.num1 = t.num1
1 голос
/ 02 февраля 2010

Просто идея:

begin tran, чтобы избежать изменений в тесте

объявить @ max int

выберите @max = max (num2) из ​​теста

создать временную таблицу с num1 и индексом автоинкремента (например: idx (начиная с 1)

вставьте свой INSERTED во временную таблицу

вставить в тест (num1, num2) выбрать num1, idx + @ max из tmp

конец транса

0 голосов
/ 02 февраля 2010
DECLARE @MAXNUM2 numeric(20)

-- First make an auto increment table starting at 1
DECLARE @tmp table 
( 
   aNum int identity(1,1),
   pInsNum varchar(10)
)

INSERT INTO @tmp (pInsNum)
  SELECT num1 FROM INSERTED;

-- Now find offset
SELECT @MAXNUM2 = MAX(num2) FROM TEST

IF @MAXNUM2 is null
BEGIN
 SET @MAXNUM2  = 0
END

-- Do update
UPDATE TEST
SET num2 = @MAXNUM2 + aNum
FROM TEST 
   INNER JOIN @tmp t ON t.pInsNum = TEST.num1

Примечание: я не смог проверить это, возможно, были опечатки.

Кроме того, я уверен, что есть решение для не-временных таблиц, использующее ROWNUMBER, но мне лень искать синтаксис. Но вы можете использовать это как руководство для получения ответа, вместо того чтобы использовать временную таблицу, чтобы числа от 1 до N использовали ROWNUMBER и добавляли это к смещению (@ maxnum2)

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