2010-02-02 50 views
3

如果我有表测试有两列NUM1NUM2和它下面的触发器,它只是增加对NUM1的刀片NUM2:SQL服务器 - 重写触发器,以避免基于游标的方法

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 
+1

触发器是魔鬼玩具。 。:D – 2010-02-02 11:53:54

回答

0
DECLARE @MAXNUM2 numeric(20) 

-- First make an auto increment table starting at 1 
DEFINE @tmp 
( 
    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 ON @tmp.pInsNum = TEST.num1 

注:我不能对此进行测试,可能会有错别字。

另外,我确定有一个使用ROWNUMBER的非临时表解决方案,但我懒得去查找语法。但是你可以用这个作为指导来得到答案,而不是使用临时表来使数字从1到N使用ROWNUMBER并将其添加到偏移量(@ maxnum2)

+0

这工作正常,但“DEFINE @tmp”应该是“DECLARE @tmp表”和内部联接应该使用别名:“INNER JOIN @tmp T ON T .pInsNum = TEST.num1“。 – pug 2010-02-03 06:40:56

+0

@pug:FYI你也可以做[@tmp],尽管我同意别名更好。 – ErikE 2010-02-07 07:53:23

1

只是一个想法:

的begin tran,以避免改变测试

声明@Max在吨

选择@Max = MAX(NUM2)从测试

创建NUM1临时表和自动增量索引(例如:IDX(从1开始)

插入您插入到临时表

插入到测试(NUM1,NUM2)选择NUM1,从TMP IDX + @最大

端TRAN

+0

有趣,我写我的时候没有看到你的答案。那么我编码这个算法(反式除外)在我的答案。有一个问题,如果你在触发器中有交易,@munissor是否有任何死锁的机会? – Hogan 2010-02-02 13:57:57

+0

是的,有死锁的可能性,触发器就像任何其他查询 – munissor 2010-02-02 15:26:40

1

如果我正确理解,一个正常更新会让你得到你想要的。

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