关于 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
 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)