【问题标题】:MSSQL Database Table Trigger not inserting records into another table after INSERT/UPDATE eventMSSQL 数据库表触发器在 INSERT/UPDATE 事件后未将记录插入另一个表
【发布时间】:2016-08-02 16:39:12
【问题描述】:

我正在开发一个 MSSQL 数据库(用于一个名为 Sage 200 的程序)。数据库中有很多表,但是,我希望通过特定表上的触发器来通知更改(插入新记录或更新现有记录)。

我还想支持同时更新此表上的多行。

当插入或更新记录时,我想从表中获取特定字段并使用该字段的值插入/更新另一个表。

所以,把它放在透视图中;触发器如下所示:

CREATE TRIGGER [dbo].[IC_CustomerLocationChanges] ON [dbo].[SLCustomerLocation]
AFTER INSERT,UPDATE
AS
BEGIN

    SELECT RowNum = ROW_NUMBER() OVER(ORDER BY SLCustomerAccountID) , SLCustomerAccountID
    INTO #CustomerLocationChanges
    FROM INSERTED;

    DECLARE @MaxRownum INT;
    SET @MaxRownum = (SELECT MAX(RowNum) FROM #CustomerLocationChanges);

    DECLARE @Iter INT;
    SET @Iter = (SELECT MIN(RowNum) FROM #CustomerLocationChanges);

    WHILE @Iter <= @MaxRownum
    BEGIN

        -- Get Customer account Id
        DECLARE @SLCustomerAccountID INT = (SELECT SLCustomerAccountID FROM #CustomerLocationChanges WHERE RowNum = @Iter);

        -- Check If Customer Doesn't Already Exist In Queue Table
        IF ((SELECT COUNT(*) FROM IC_CustomerUpdates WITH (NOLOCK) WHERE SLCustomerAccountID = @SLCustomerAccountID) > 0)
        BEGIN

            -- Insert new record
            print 'Insert [CustomerCreate] Queue Entry | SLCustomerAccountID : ' + CAST(@SLCustomerAccountID AS VARCHAR(255));
            INSERT INTO IC_CustomerUpdates (SLCustomerAccountID, Synced) VALUES
            (@SLCustomerAccountID, 0);

        END
        ELSE
        BEGIN

            -- Update existing record
            print 'Update [CustomerCreate] Queue Entry | SLCustomerAccountID : ' + CAST(@SLCustomerAccountID AS VARCHAR(255));
            UPDATE IC_CustomerUpdates SET Synced = 0 
            WHERE SLCustomerAccountID = @SLCustomerAccountID;

        END

        SET @Iter = @Iter + 1;

    END

    DROP TABLE #CustomerLocationChanges;

END
GO

为了测试这一点,我运行了以下查询:

update SLCustomerLocation SET AddressLine2 = AddressLine2 + ' test' 
where SLCustomerAccountID = 1019

select * from IC_CustomerUpdates

这不会从我的 IC_CustomerUpdates 中返回任何行:

这是我在消息窗口中看到的:

这意味着触发器尚未将记录插入到我的队列表中。有什么想法可能是错的吗?

【问题讨论】:

  • 这个条件不是:IF ((SELECT COUNT(*) FROM IC_CustomerUpdates WITH (NOLOCK) WHERE SLCustomerAccountID = @SLCustomerAccountID) &gt; 0) 意味着如果该表中已经存在该客户的行,您将只插入行?
  • 您可以(并且可能应该)将其重写为基于集合的操作而不是 RBAR。而且确实没有理由将插入的内容放入临时表中。您已经有一个副本,无需创建另一个。小心那些 NOLOCK 提示......它们不仅仅是脏读。 blogs.sqlsentry.com/aaronbertrand/bad-habits-nolock-everywhere
  • @Lamak - 是的,你是对的。那个条件是错误的。应该是:IF ((SELECT COUNT(*) FROM IC_CustomerUpdates WITH (NOLOCK) WHERE SLCustomerAccountID = @SLCustomerAccountID) = 0) - 刚刚测试过;现在工作正常。很抱歉,愚蠢的错字导致整个触发器不起作用......
  • @SeanLange 我计划将此提交给代码审查以征求意见。我还需要在其他几个表上使用完全相同的触发器,所以不知道如何在不为每个表重复相同的触发器代码的情况下实现这一点。
  • 好的,现在可以了。但是有很多地方需要改进。有SET @Iter = (SELECT MIN(RowNum) FROM #CustomerLocationChanges);之类的细节,你第一次设置这个变量不应该只是SET @Iter = 1吗?无论如何,整个事情都可以改写为基于设置

标签: sql-server triggers database-trigger


【解决方案1】:

@Lamak 看起来是正确的;偶然发现这一点有点晚,但也许这些信息会对其他人有所帮助。

Sicon 开发了一个帮助审核更改的第 3 方插件。这可能涵盖您需要的内容。

大多数与 Sage 200 的集成使用每个表中的 OpLock 字段来确定最后编辑日期。

SLCustomerLocation 表可以为单个 SLCustomerAccountID 保存多条记录,因此您可能需要在脚本中考虑到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-20
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多