SQL: триггер не собирает все строки - PullRequest
1 голос
/ 14 апреля 2020

У меня проблема с триггером, который должен обновлять одну таблицу, когда в другой таблице появляется новая строка.

У меня есть две таблицы:

Первая:

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

И вторая:

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

В таблицу [Events] идет каждое изменение статуса на каждой машине, которая пришла от Stream Analytics. С каждой новой строкой вторая таблица должна обновляться и показывать последнее значение для каждой машины с последней меткой времени в StatusLastRefre sh. На самом деле таблица [ActualParams] имеет 4 строки данных.

Я пробовал сделать два триггера:

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

, но ни один из них не работает на 100% правильно.

Во-первых, триггер Merge работает нормально, когда вставленные строки по одной для каждого MachineName одновременно, но иногда для нескольких новых строк одновременно тот же самый MachineName вставлен, и я получаю сообщение об ошибке, что он не может записать много строк в одну одновременно, и все застревает.

Второй, более простой триггер Update иногда пропускает строку, а в таблице ActualParams есть предыдущий Значение StatusId, не актуально. На самом деле у меня есть 4 машины, и обычно одна из них имеет неправильный StatusId. Интересно, что произойдет, когда будет 20 или более машин?

MachineName уникален для каждой машины.

Я пробовал CURSOR с UPDATE, но иногда строка пропускается, и статус не актуально.

Я не знаю, как объединить CURSOR с MERGE, и, возможно, это будет решением для этого.

Он должен реагировать на каждую строку, потому что я также хочу суммировать количество во второй таблице, поэтому я не могу пропустить ни одной строки (забыл об этом ранее - отредактировано)

Есть идеи? Я использую SSMS 17.

1 Ответ

0 голосов
/ 14 апреля 2020

Почему бы вам просто не написать это с update / join?

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

Если один и тот же компьютер может обновляться несколько раз за один insert, тогда используйте оконные функции для получить последний ряд:

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;
...