关于 SQL Server:SQL Server – 重写触发器以避免基于游标的方法
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 WHILE @@FETCH_STATUS = 0 SELECT @NEWNUM2 = MAX(num2) FROM TEST CLOSE 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 |
相关讨论
- 触发器是魔鬼的玩物......:D
如果我理解正确,正常的更新会得到你想要的。
|
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
结束传输
相关讨论
- 有趣的是,我写我的时候没有看到你的答案。好吧,我在答案中编写了这个算法(trans 除外)。一个问题@munissor 如果触发器中有事务,是否有可能出现死锁?
- 是的,有死锁的可能性,触发器就像任何其他查询一样
|
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 INSERT INTO @tmp (pInsNum) -- Now find offset IF @MAXNUM2 IS NULL -- Do update |
注意:我无法对此进行测试,可能有错别字。
另外,我确信有一个使用 ROWNUMBER 的非临时表解决方案,但我懒得去查找语法。但是您可以将其用作获得该答案的指南,而不是使用临时表使从 1 到 N 的数字使用 ROWNUMBER 并将其添加到偏移量 (@maxnum2)
相关讨论
- 这工作正常,但 "DEFINE @tmp" 应该是 "DECLARE @tmp Table" 并且内部连接应该使用别名:"INNER JOIN @tmp T ON T.pInsNum = TEST.num1"。
- @pug:仅供参考,您也可以 [@tmp] 尽管我同意别名更好。