SQL Server - Rewrite trigger to avoid cursor based approach
如果我有两列 num1 和 num2 的表 Test 以及下面的触发器,它只会在插入 num1 时增加 num2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 及更高版本):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
如果我理解正确,正常的更新会得到你想要的。
1 2 3 4 | UPDATE TEST SET num2 = @NEWNUM2 FROM TEST t INNER JOIN Inserted i ON i.num1 = t.num1 |
只是一个想法:
开始 tran 以避免更改 test
声明@max int
从测试中选择@max = max(num2)
用 num1 和自增索引创建一个临时表(例如:idx(从 1 开始)
将你的 INSERTED 插入到临时表中
insert into test(num1, num2) select num1, idx @max from tmp
结束传输
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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)