更新后更新触发器逻辑

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了更新后更新触发器逻辑相关的知识,希望对你有一定的参考价值。

我在触发器中遇到了错误的逻辑。我在基表上更新后插入到Audit表中的记录数量错误。以下是重新创建此问题的代码段。

create table #T1 (id int NOT NULL, CODE varchar(3) NOT NULL, pkID INT NOT NULL)
insert into #T1 (id, CODE, pkID)
values(1, 'vak', 1989),(2,'Vl2',1988), (2,'Vl2',1988)--, (null, 'Gotik')
go

create table #T2 (id int NOT NULL, CODE varchar(3) NOT NULL, pkID INT NOT NULL)
insert into #T2 (id, CODE, pkID)
values(101, 'vas', 1979),(105,'va3',1973), (4,'va5',1888),  (4,'va5',1888)--, (null, 'Popik') 
go 

create table [MyDB].dbo.Test_Dec22nd2017 (id int NOT null CONSTRAINT PK_TEST PRIMARY KEY, Ln varchar(10) null)
insert into [MyDB].dbo.Test_Dec22nd2017 (id, ln)

values (1, 'vasya1'),(2,'vasya3'), (4,'vasya2'),(5,'Super'), (6,'LYAYA'), (105,'TERSDF'), (101,'DFSDS')
go 


DROP TRIGGER DBO.TR_TEST_DEC22nd2017
GO
CREATE TRIGGER DBO.TR_TEST_DEC22nd2017
ON [dbo].[Test_Dec22nd2017] AFTER INSERT, DELETE, UPDATE
    NOT FOR REPLICATION

AS 
BEGIN 

    IF NOT EXISTS ( SELECT TOP 1 1 FROM 
                                inserted ins
                    FULL OUTER JOIN deleted del ON ins.ID = del.ID
                    INNER JOIN 
                    [MyDB].dbo.Test_Dec22nd2017 a ON a.id = ISNULL(ins.ID, del.ID)
                    INNER JOIN #T1 t ON t.id = a.id
                    LEFT JOIN #T2 t2 ON t2.id = a.id
                    --WHERE t.id IS NULL AND t2.id IS NULL 
                )

        BEGIN

            WITH CTE2 AS (
                    SELECT 
                        ISNULL(ins.ID, del.ID) AS ID,
                        CASE 
                            WHEN ins.ID IS NOT NULL AND del.ID IS NOT NULL THEN 'UPDATE' 
                            WHEN ins.ID IS NOT NULL THEN 'INSERT'
                            ELSE 'UPDATE' END
                        AS AuditType  
                    FROM inserted ins 
                    FULL OUTER JOIN deleted del 
                            ON ins.ID = del.ID
                    ) 

            ,AUDIT_CTE2 AS (    
                    SELECT DISTINCT     
                        CTE2.ID, 
                        'OVC' AS Code,
                        CTE2.AuditType
                    FROM CTE2
                    --  WHERE ID IS NOT NULL
                        )

                    INSERT [MyDB].[dbo].[AuditTable] (Code, ID, AuditType)/*, ParentCode, ParentID)*/
                    SELECT
                        Code,
                        ID, 
                        AuditType
                    FROM AUDIT_CTE2
        END 

    IF EXISTS ( SELECT TOP 1 1 FROM 
                                inserted ins -- ISNULL(T.pkID, t2.pkID)
                    FULL OUTER JOIN deleted del ON ins.ID = del.ID
                    INNER JOIN 
                    [MyDB].dbo.Test_Dec22nd2017 a ON a.id = ISNULL(ins.ID, del.ID)
                    LEFT JOIN #T1 t ON t.id = a.id
                    LEFT JOIN #T2 t2 ON t2.id = a.id
                    WHERE t.id IS NOT NULL OR t2.id IS NOT NULL
                ) 

        BEGIN

            WITH CTE AS (
                SELECT 
                    ISNULL(ins.ID, del.ID) AS ID,
                    CASE 
                        WHEN ins.ID IS NOT NULL AND del.ID IS NOT NULL THEN 'UPDATE' 
                        WHEN ins.ID IS NOT NULL THEN 'INSERT'
                        ELSE 'UPDATE' END
                    AS AuditType  
                FROM inserted ins 
                FULL OUTER JOIN deleted del 
                        ON ins.ID = del.ID
                        ) 

            ,AUDIT_CTE AS ( 
                    SELECT DISTINCT     
                        CTE.ID, 
                        'TST' AS Code,
                        CTE.AuditType,
                        ISNULL(T.CODE,T2.CODE) AS ParentCode,
                        ISNULL(T.pkID, T2.pkID) AS ParentID
                    FROM CTE
                    INNER JOIN MyDB.dbo.Test_Dec22nd2017 a ON CTE.ID = a.id
                    LEFT OUTER JOIN #T1 T ON T.id = a.id
                    LEFT OUTER JOIN #T2 T2 ON T2.id = a.id 
                    WHERE T.pkID IS NOT NULL OR T2.pkID IS NOT NULL
                        )

                    INSERT [MyDB].[dbo].[AuditTable] (Code, ID, AuditType, ParentCode, ParentID)
                    SELECT
                        Code,
                        ID, 
                        AuditType,
                        ParentCode,
                        ParentID
                    FROM AUDIT_CTE
        END 
END

这是导致在Audit表中插入两个错误记录的原因

GO
UPDATE [MyDB].dbo.Test_Dec22nd2017
SET Ln = 'DDD' WHERE ID 
IN (101,105,11)
SELECT TOP 30 * FROM  [MyDB].[dbo].[AuditTable] ORDER BY 1 DESC

enter image description here

enter image description here

从上面的图片中可以看出,它在搜索审计表中插入了5行。但是应该只插入3.一个用于ID 6,父代码= Null,ParentID = NULL,两个记录用于ID 101和105,ParentID为1973和1979以及相应的父代码。

这两个陈述完全正常。

insert into [MyDB].dbo.Test_Dec22nd2017 (id, ln)
values (44,'vasya1'), (45,'vasya2')
SELECT TOP 30 * FROM  [MyDB].[dbo].[AuditTable] ORDER BY 1 DESC

GO

UPDATE [MyDB].dbo.Test_Dec22nd2017
SET Ln = 'DDD' WHERE ID
IN (5,10,6)
SELECT TOP 30 * FROM  [MyDB].[dbo].[AuditTable] ORDER BY 1 DESC
答案

您可以将触发器中的第一个IF NOT EXISTS更改为:

IF EXISTS (SELECT TOP 1 1 FROM 
                inserted ins
    FULL OUTER JOIN deleted del ON ins.ID = del.ID
    INNER JOIN 
    [tempdb].dbo.Test_Dec22nd2017 a ON a.id = ISNULL(ins.ID, del.ID)
    LEFT JOIN #T1 t ON t.id = a.id
    LEFT JOIN #T2 t2 ON t2.id = a.id
    WHERE t.id IS NULL AND t2.id IS NULL 
)

忽略#T1或#T2中存在的任何ID

以上是关于更新后更新触发器逻辑的主要内容,如果未能解决你的问题,请参考以下文章

导致活动不工作的片段中的按钮(更新)

jQuery 更改为隐藏字段后,在 Gravity Forms 中触发表单更新

触发检查逻辑日期更新

运行后取消主触发器(更新后)触发器类型

postgreSQL创建一个触发器函数:更新过student1表的数据后,更新student1_stats表中数据。

在更新后触发器上获取更新列名的有效方法