SQL: 触发器没有收集每一行

SQL: Trigger is not collecting every row

我的触发器有问题,当我在另一个 table 中有新行时应该更新一个 table。

我有两个 table:

第一个:

SELECT 
    [Id], [Timestamp], [MachineName], [StatusId], [Quantity]
FROM [dbo].[Events]

第二个:

SELECT 
    [Id], [MachineName], [StatusId], [QuantitySum], [StatusLastRefresh]
FROM [dbo].[ActualParams]

到 table [Events] 每台机器上的每个状态更改都来自流分析。对于每个新行,第二个 table 应该更新并显示每台机器的最后一个值,最后一个时间戳在 StatusLastRefresh 中。实际上table[ActualParams]有4行数据

我已经尝试了 2 个触发器:

ALTER TRIGGER [dbo].[AfterInsertEvent] 
ON [dbo].[Events] 
AFTER INSERT
AS 
    MERGE ActualParams AS ap
    USING (SELECT Id, Machine, Status, Timestamp, Quantity 
           FROM inserted) AS ev ON ev.MachineName = ap.MachineName

    WHEN MATCHED THEN
       UPDATE SET map.StatusId = ev.StatusId, 
                  ap.StatusLastRefresh = ev.Timestamp, 
                  ap.QuantitySum = ap.QuantitySum + ev.Quantity;

触发器#2:

ALTER TRIGGER [dbo].[AfterInsertEvent] 
ON [dbo].[Events] 
AFTER INSERT
BEGIN
    DECLARE @mn nchar(10), @si int, @ts datetime2(7), @q int

    SELECT @mn = MachineName, @si = StatusId, @ts = Timestamp, @q = Quantity 
    FROM inserted

    UPDATE ActualParams
    SET StatusId = @si, 
        StatusLastRefresh = @ts, 
        QuantitySum = QuantitySum + @q  
    WHERE ActualParams.MachineName = @mn
END

但其中 none 100% 正确。

首先,当每个 MachineName 插入的行同时插入一个行时,Merge 触发器工作正常,但有时对于相同的 [=18],同时插入的行很少=] 已插入,我收到一个错误,它无法同时将多行写入一个行,一切都卡住了。

其次,更简单的 Update 触发器有时会跳过一行,并且在 ActualParams table 中有以前的 StatusId 值,而不是实际值。实际上我有 4 台机器,通常其中一台有错误的 StatusId。我想知道当有20台或更多台机器时会发生什么。

MachineName 对每台机器都是唯一的。

我尝试使用 CURSOR 和 UPDATE,但有时仍然会跳过该行,并且状态不真实。

我不知道如何将 CURSOR 与 MERGE 结合使用,也许这就是解决方案。

它必须对每一行做出反应,因为我还想在第二个 table 中汇总数量,所以这就是为什么我不能跳过任何行(之前忘记了 - 已编辑)

有什么想法吗?我正在使用 SSMS 17。

你为什么不直接用 update/join 来写呢?

UPDATE ap
    SET StatusId = i.StatusId,
        StatusLastRefresh = i.TimeStamp
    FROM ActualParams ap
         inserted i
         ON ap.MachineName = i.MachineName;

如果同一台机器可以在一台insert中更新多次,则使用window函数获取最后一行:

UPDATE ap
    SET StatusId = i.StatusId,
        StatusLastRefresh = i.TimeStamp
    FROM ActualParams ap
         (SELECT i.*,
                 ROW_NUMBER() OVER (PARTITION BY MachineName ORDER BY TimeStamp DESC) as seqnum
          FROM inserted i
         ) i
         ON ap.MachineName = i.MachineName AND seqnum = 1;