Триггер после вставки не работает правильно после нескольких вставок - PullRequest
1 голос
/ 01 апреля 2019

У меня есть триггер, который срабатывает после вставки. Он запускает хранимую процедуру, которая обновляет столбец IsLast в таблице CompanyStatus

Id | CompanyId | Status | DateCreated | IsLast

Эта хранимая процедура должна установить 1 в столбце IsLast для записи с наибольшим Id.

CREATE PROCEDURE [dbo].[spCompanyStatusAfterInsert](@schemaName nvarchar(100),  @dataTable CompanyStatus READONLY)
AS
BEGIN
    DECLARE @sql nvarchar(max)

    SELECT @sql = N'DECLARE
        @Id bigint,
        @companyId uniqueidentifier;

        DECLARE CompanyStatus_Cursor CURSOR FAST_FORWARD FOR
        SELECT Id, CompanyId
        FROM @dataTable

        OPEN CompanyStatus_Cursor 

        FETCH NEXT FROM CompanyStatus_Cursor 
        INTO @Id, @companyId

        WHILE @@FETCH_STATUS = 0
        BEGIN
            UPDATE ' + QUOTENAME(@schemaName ) + N'.[CompanyStatus]
            SET IsLast = 0
            WHERE Id IN (SELECT Id
                         FROM ' + QUOTENAME(@schemaName) + N'.[CompanyStatus]
                         WHERE Id <> @Id
                               AND CompanyId = @companyId
                               AND IsLast = 1) 

            UPDATE ' + QUOTENAME(@schemaName) + N'.[CompanyStatus]
            SET IsLast = 1
            WHERE Id = @Id

            FETCH NEXT FROM crs
            INTO @Id, @companyId
        END

        CLOSE CompanyStatus_Cursor 
        DEALLOCATE CompanyStatus_Cursor'

    EXEC sp_executesql @sql, N'@schemaName nvarchar(100), @dataTable CompanyStatus READONLY', @schemaName, @dataTable
END

(Сначала обновите все существующие IsLast до 0, а затем установите 1 до последнего Id - это ожидаемое поведение).

Проблема - когда я делаю 2 вставки за очень короткое время, в результате я получаю 2 записи с IsLast = 1.

Id | CompanyId                            | Status | DateCreated             | IsLast
19 | 8afbd9cb-02f9-45d7-a605-a54052866bd4 | 1      | 2019-04-01 12:08:59.540 | 1
18 | 8afbd9cb-02f9-45d7-a605-a54052866bd4 | 1      | 2019-04-01 12:10:57.790 | 1
17 | fc7d1f2b-a72a-4d7f-99fa-602c72fb0410 | 2      | 2019-03-30 12:14:57.294 | 1
16 | 8afbd9cb-02f9-45d7-a605-a54052866bd4 | 1      | 2019-03-29 12:10:57.790 | 0

В примере строка с идентификатором 18 не должна быть с IsLast = 1, поскольку есть строка с большим идентификатором.


Есть ли проблема во время выполнения этого update-запроса? (первое обновление не закончено до запуска второго).


Триггерный код:

CREATE TRIGGER [{schema}].[{schema}_TRG_CompanyStatus]
ON [{schema}].[CompanyStatus]
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON

    DECLARE @dataTable CompanyStatus

    INSERT INTO @dataTable SELECT Id, CompanyId  FROM inserted

    EXEC [dbo].[spCompanyStatusAfterInsert] N'{schema}', @dataTable
END

GO

1 Ответ

0 голосов
/ 04 апреля 2019

проверить это

CREATE PROCEDURE [dbo].[spCompanyStatusAfterInsert](@schemaName nvarchar(100),  @dataTable CompanyStatus READONLY)
AS
BEGIN
    DECLARE @sql nvarchar(max)

    SELECT @sql = N'

            UPDATE tab
            SET IsLast = CASE src.id WHEN tab.id THEN 1 ELSE 0 END

            FROM ' + QUOTENAME(@schemaName ) + N'.[CompanyStatus] tab
            INNER JOIN @dataTable src
            ON tab.CompanyId = src.companyId
            WHERE tab.id = src.id or tab.IsLast=1
    '

    EXEC sp_executesql @sql, N'@schemaName nvarchar(100), @dataTable CompanyStatus READONLY', @schemaName, @dataTable
END
...