【问题标题】:Cursor on a trigger触发器上的光标
【发布时间】:2018-05-27 22:17:18
【问题描述】:

我使用的是 SQL Server 2008。

我在表中定义了一个用于 INSERT、UPDATE 和 DELETE 操作的后触发器。我的问题是,目前我的触发器一次插入一条记录,我需要多条记录作为一个

SELECT TOP 1 @ParentID FROM ... WHERE ID = @ID 

返回多个唯一记录。

(请参阅下面的评论“--此子查询返回超过 1 个值,因此我需要在搜索审核表中插入与返回一样多的 ParentID”)

我认为我需要使用游标,但我不确定在哪里声明和打开游标。

--CREATE PROCEDURE [dbo].[SP_Auditing]
--      @ID INT, @Code VARCHAR(3), @AuditType VARCHAR(10), @ParentCode VARCHAR(3) = NULL, @ParentID INT = NULL
--AS
--BEGIN
--          INSERT INTO myDB.dbo.Table1 (ID, Code, AuditType, ParentCode, ParentID)

--          VALUES(@ID, @Code, @AuditType, @ParentCode, @ParentID)
--END

GO

CREATE TRIGGER [dbo].[Tr_MyFavouriteTable_UPD_INSERT_DEL]    ON [dbo].[MyFavouriteTable] AFTER INSERT, DELETE, UPDATE    NOT FOR REPLICATION 

AS   

BEGIN
            DECLARE @ID INT,            @Code VARCHAR(3),           @AuditType VARCHAR(10),             @ParentCode VARCHAR(3),             @ParentID INT       SET     @Code = 'DOC'

    IF EXISTS (SELECT 1 FROM inserted)          AND 
       NOT EXISTS (SELECT 1 FROM deleted) 
                BEGIN 
                        SELECT TOP 1  
                @ID = ins.ID, 
                @ParentID = (
                    SELECT TOP 1 CAST(RIGHT(parentId,LEN(parentId) - LEN(LEFT(parentId,3))) AS INT) 
                    FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
                    INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK)
                        ON t.Id = v.ID
                    WHERE v.ID = @ID --284 
                ), **-- this subquery returns more than 1 value, so I need to insert in the search Audit table as many ParentIDs as it returns**
                @AuditType = 'INSERT'           FROM inserted ins
                        IF @ID IS NOT NULL 
               AND 
               @ParentID IS NOT NULL
               AND 
               @ParentCode IS NOT NULL    

            EXEC [MyDB].[dbo].SP_Auditing] @ID, @Code, @AuditType, @ParentCode, @ParentID 
                END

--  below is the same logic for UPDATE and DELETE actions...

上面的存储过程只是将数据插入到审计表中。

【问题讨论】:

标签: sql-server variables triggers cursor


【解决方案1】:

为什么要一一获取记录?据我了解,您希望保留日志。

IF EXISTS (SELECT 1 FROM inserted)          AND 
   NOT EXISTS (SELECT 1 FROM deleted) 
            BEGIN 
            INSERT INTO [Your_Log_Table] 
            SELECT
            ins.ID, [Code],'INSERT',[PrentCode],
            (SELECT TOP 1 CAST(RIGHT(parentId,LEN(parentId) - 
                LEN(LEFT(parentId,3))) AS INT) 
                FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
                INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK)
                    ON t.Id = v.ID
                WHERE v.ID = ins.ID --284 
            )
                FROM inserted ins
            END      

【讨论】:

  • 我的审核表有一个ID到多个唯一ParentID的原因。
  • 那么上面的查询会为每个 ID 提供一个 ParentID。
【解决方案2】:

切勿在触发器中使用标量变量,因为插入、更新和删除可能会影响多行。至于你的触发器,试试这样的。

CREATE TRIGGER [dbo].[Tr_MyFavouriteTable_UPD_INSERT_DEL]
    ON [dbo].[MyFavouriteTable] AFTER INSERT, DELETE, UPDATE
        NOT FOR REPLICATION 
AS   

BEGIN
    ;with act as (
    select isnull(i.id,d.id) id, --either deleted or inserted is not null
    case when i.id is not null and d.id is not null then 'update'
         when i.id is not null then 'insert'
         else 'delete' end auditType
    from inserted i full outer join deleted d on i.id = d.id
    ),
    audit_cte as (
    SELECT act.id, 'DOC' Code,
           CAST(RIGHT(parentId,LEN(parentId) - LEN(LEFT(parentId,3))) AS INT) parentid,
           act.auditType, 'parentcode' parentCode
    FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
    INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK)  ON t.Id = v.ID
    inner join act on act.id = t.id
    )
    insert myDB.dbo.Table1 (ID, Code, AuditType, ParentCode, ParentID)
    select id,code,AuditType, ParentCode, ParentID
    from audit_cte
    where parentCode is not null and parentid is not null
end

【讨论】:

  • 伟大的亚历克斯。只有一件事困扰我,当 ParentID 相同时它会记录重复记录。只有当 ParentID 不同时,我才需要记录所有记录;否则,我只需要为 ParentID 记录一条记录。这里的逻辑是一个ID可能有多个ParentID但只有一个ParentCode
  • 为了避免上述问题,我在您的 audit_cte 下方又添加了一个 CTE,并使用 ROW_NUMBER() 来整理重复项。非常感谢亚历克斯!
【解决方案3】:

查看 Alex Kudryashev 的回答。我需要稍微调整一下他的逻辑,以整理出具有相同 ParentID 的重复记录,以便插入到 Audit 表中。我在 Alex 的 cte_Audit 下方又添加了一个 cte,如下所示

CREATE TRIGGER [dbo].[Tr_MyFavouriteTable_UPD_INSERT_DEL]
    ON [dbo].[MyFavouriteTable] AFTER INSERT, DELETE, UPDATE
        NOT FOR REPLICATION 
AS   

BEGIN
    ;with act as (
    select isnull(i.id,d.id) id, --either deleted or inserted is not null
    case when i.id is not null and d.id is not null then 'update'
         when i.id is not null then 'insert'
         else 'delete' end auditType
    from inserted i full outer join deleted d on i.id = d.id
    ),
    audit_cte as (
    SELECT act.id, 'DOC' Code,
           CAST(RIGHT(parentId,LEN(parentId) - LEN(LEFT(parentId,3))) AS INT) parentid,
           act.auditType, 'parentcode' parentCode
    FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
    INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK)  ON t.Id = v.ID
    inner join act on act.id = t.id
    )
    insert myDB.dbo.Table1 (ID, Code, AuditType, ParentCode, ParentID)
    select id,code,AuditType, ParentCode, ParentID
    from audit_cte
    where parentCode is not null and parentid is not null
         ,CTE_dupsCleanup AS (
                SELECT DISTINCT
                Code,
                Id, 
                AuditType,
                ParentCode,
                ParentId,

  --   ROW_NUMBER() OVER(PARTITION BY ParentId, ParentCode, AuditType ORDER BY ParentId) AS Rn

        FROM AUDIT_CTE 
                WHERE ParentCode IS NOT NULL 
                    AND ParentId IS NOT NULL )


Then using Rn = 1 inserted only unique records into the Auidt table. Like this: 

                    INSERT [ISSearch].[dbo].[SearchAudit] (Code, ID, AuditType, ParentCode, ParentID)
                SELECT
                Code,
                ID, 
                AuditType,
                ParentCode,
                ParentId
                FROM CTE_dupsCleanup 
                --  WHERE Rn = 1
END

【讨论】:

    猜你喜欢
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多