TSQL触发器不保存变量和/或没有正确执行

时间:2010-11-29 08:45:15

标签: sql-server tsql

我无法让TSQL触发器正常工作。我已经通过调试器运行它,并且它没有根据SQL Server Management Studio设置任何变量。最糟糕的事情是触发器本身正确执行,执行时没有错误(只是说'执行成功')。

代码如下(这是一项正在进行的工作......只是让我自己熟悉):

USE TestDb

IF EXISTS (SELECT name FROM sysobjects
      WHERE name = 'OfficeSalesQuotaUpdate' AND type = 'TR')
   DROP TRIGGER OfficeSalesQuotaUpdate
GO

CREATE TRIGGER OfficeSalesQuotaUpdate
ON SalesReps
AFTER UPDATE, DELETE, INSERT 
AS
    DECLARE @sales_difference int,  @quota_difference int
    DECLARE @sales_original int,    @quota_original int
    DECLARE @sales_new int,         @quota_new int

    DECLARE @officeid int
    DECLARE @salesrepid int

    --UPDATE(Sales) returns true for INSERT and UPDATE.
    --Not for DELETE though.    

    IF ((SELECT COUNT(*) FROM inserted) = 0)
        SET @salesrepid = (SELECT SalesRep FROM deleted)
    ELSE    
        SET @salesrepid = (SELECT SalesRep FROM inserted)   

    --If you address the @salesrepid variable, it does not work. Doesn't even 
    --print out the 'this should work line.
    PRINT 'This should work...' --+ convert(char(30), @salesrepid)

    IF (@salesrepid = NULL)
        PRINT 'SalesRepId is null'
    ELSE
        PRINT 'SalesRepId is not null'

    PRINT convert(char(50), @salesrepid)


    SET @officeid = (SELECT RepOffice 
                       FROM SalesReps 
                      WHERE SalesRep = @salesrepid)

    SELECT @sales_original =    (SELECT Sales FROM deleted)
    SELECT @sales_new =         (SELECT Sales FROM inserted)

    --Sales can not be null, so we'll remove this later.
    --Use this as a template for quota though, since that can be null.
    IF (@sales_new = null) 
    BEGIN
        SET @sales_new = 0
    END

    IF (@sales_original = 0)
    BEGIN
        SET @sales_original = 0
    END

    SET @sales_difference = @sales_new - @sales_original

    UPDATE Offices
    SET Sales = Sales + @sales_difference
    WHERE Offices.Office = @officeid
GO

那么,有什么提示吗?我完全不知道这个。提前谢谢。

3 个答案:

答案 0 :(得分:2)

您的主要问题似乎是@foo = NULL@foo IS NULL之间存在差异:

declare @i int
set @i = null -- redundant, but explicit

if @i = null print 'equals'
if @i is null print 'is'

'This should working'PRINT语句不起作用,因为将NULL与字符串连接会产生NULL,而PRINT NULL不会打印任何内容。

至于实际设置@salerepid的值,似乎很可能插入和/或删除的表实际上是空的。您使用什么语句来测试触发器?你打印出COUNT(*)值吗?

如果有人一次更改多行,您还应该考虑(如果您还没有)。您当前的代码假定一次只更改一行,这在您的环境中可能是合理的假设,但如果有人批量加载数据或进行其他“批处理”,则很容易中断。

最后,你应该经常提到你的MSSQL版本和版本;它可能与某些语法问题有关。

答案 1 :(得分:2)

你应该用这样的东西替换触发器的主体:

;WITH Totals AS (
     SELECT RepOffice,SUM(Sales) as Sales FROM inserted GROUP BY RepOffice
     UNION ALL
     SELECT RepOffice,-SUM(Sales) FROM deleted GROUP BY RepOffice
), SalesDelta AS (
     SELECT RepOffice,SUM(Sales) as Delta FROM Totals GROUP BY RepOffice
)
UPDATE o
SET Sales = Sales + sd.Delta
FROM
    Offices o
        inner join
    SalesDelta sd
        on
             o.Office = sd.RepOffice

这将充分应对插入和删除的多行。我假设SalesRep是SalesReps表的主键。


上面更新,以应对UPDATE更改特定销售代表的RepOffice(原始版本没有,可以推测,也是正确的)

答案 2 :(得分:0)

只是一个建议......您是否尝试过将BEGIN和END封装到触发器的“AS”部分?