SQL Server - 重写触发器以避免基于游标的方法

时间:2010-02-02 11:52:42

标签: sql sql-server tsql

如果我的表测试有两列 num1 num2 ,并且其上有以下触发器,它只会在num1的插入上增加num2:

 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 A trigger to work on multiple row inserts

使用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 个答案:

答案 0 :(得分:1)

只是一个想法:

开始转换以避免更改测试

声明@max int

从测试中选择@max = max(num2)

使用num1和autoincrement index创建一个临时表(例如:idx(从1开始)

将INSERTED插入临时表

插入测试(num1,num2)从tmp选择num1,idx + @max

end tran

答案 1 :(得分:1)

如果我理解正确,那么正常的更新会让你得到你想要的东西。

UPDATE  TEST
SET     num2 = @NEWNUM2
FROM    TEST t
        INNER JOIN Inserted i ON i.num1 = t.num1

答案 2 :(得分:0)

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)