插入更新触发器如何确定是否插入或更新

MSI*_*SIL 155 t-sql sql-server triggers

我需要在表A上编写一个Insert,Update Trigger,它将删除表B中的所有行,其中一列(比如Desc)的值类似于表A列中插入/更新的值(比如Col1).我将如何编写它以便我可以处理Update和Insert案例.如何确定是否为更新或插入执行了触发器.

gbn*_*gbn 160

如果是MS SQL Server ......

触发器具有特殊INSERTEDDELETED表格来跟踪"之前"和"之后"数据.所以你可以使用类似的东西IF EXISTS (SELECT * FROM DELETED)来检测更新.您只有DELETED更新中的行,但总是有行INSERTED.

CREATE TRIGGER中查找"inserted"

编辑,2011年11月23日

评论后,这个答案仅适用于INSERTEDUPDATED触发.
显然,INSERTED正如我上面所说,DELETE触发器不能有"总是在行中"


net*_*rog 121

CREATE TRIGGER dbo.TableName_IUD
ON dbo.TableName
AFTER INSERT, UPDATE, DELETE
AS 
BEGIN
    SET NOCOUNT ON;

    --
    -- Check if this is an INSERT, UPDATE or DELETE Action.
    -- 
    DECLARE @action as char(1);

    SET @action = 'I'; -- Set Action to Insert by default.
    IF EXISTS(SELECT * FROM DELETED)
    BEGIN
        SET @action = 
            CASE
                WHEN EXISTS(SELECT * FROM INSERTED) THEN 'U' -- Set Action to Updated.
                ELSE 'D' -- Set Action to Deleted.       
            END
    END
    ELSE 
        IF NOT EXISTS(SELECT * FROM INSERTED) RETURN; -- Nothing updated or inserted.

    ...

    END
Run Code Online (Sandbox Code Playgroud)

  • IF EXISTS(SELECT*...)和IF EXISTS(SELECT 1)...具有完全相同的性能.根本不读取也不取出行.事实上,您也可以使用IF EXISTS(SELECT 1/0 ...),它仍然可以工作,不会导致除零错误. (24认同)
  • 我正在为插入、更新和删除创建单独的触发器。现在很高兴知道它们可以组合! (2认同)
  • 如果有人向INSERT和DELETE两个不同的行写入查询(在同一脚本中插入新行并删除另一行),按上述方式设置的触发器是否可能会将其实际标识为UPDATE(即使意图是实际上不是更新),因为已插入/删除的sql表中有数据? (2认同)

Mik*_*Vee 78

如果您运行删除任何内容的删除语句,其中许多建议都不会考虑.
假设您尝试删除ID等于表中不存在的某个值的位置.
仍会调用您的触发器,但"已删除"或"已插入"表中没有任何内容.

使用它是安全的:

--Determine if this is an INSERT,UPDATE, or DELETE Action or a "failed delete".
DECLARE @Action as char(1);
    SET @Action = (CASE WHEN EXISTS(SELECT * FROM INSERTED)
                         AND EXISTS(SELECT * FROM DELETED)
                        THEN 'U'  -- Set Action to Updated.
                        WHEN EXISTS(SELECT * FROM INSERTED)
                        THEN 'I'  -- Set Action to Insert.
                        WHEN EXISTS(SELECT * FROM DELETED)
                        THEN 'D'  -- Set Action to Deleted.
                        ELSE NULL -- Skip. It may have been a "failed delete".   
                    END)
Run Code Online (Sandbox Code Playgroud)

特别感谢@KenDog和@Net_Prog的回答.
我从他们的脚本中构建了这个.

  • 这个是奖品,处理不存在的删了。干得好! (4认同)
  • 我们也可能有一个不影响任何行的UPDATE(甚至是INSERT). (4认同)

Sat*_*Sat 17

我正在使用以下内容,它还正确检测删除任何内容的删除语句:

CREATE TRIGGER dbo.TR_TableName_TriggerName
    ON dbo.TableName
    AFTER INSERT, UPDATE, DELETE
AS
BEGIN
    SET NOCOUNT ON;

    IF NOT EXISTS(SELECT * FROM INSERTED)
        -- DELETE
        PRINT 'DELETE';
    ELSE
    BEGIN
        IF NOT EXISTS(SELECT * FROM DELETED)
            -- INSERT
            PRINT 'INSERT';
        ELSE
            -- UPDATE
            PRINT 'UPDATE';
    END
END;
Run Code Online (Sandbox Code Playgroud)

  • 但是,这个错误地检测到什么都不插入或者什么都不更新的语句 (3认同)

小智 11

经过大量搜索后,我找不到单个SQL Server触发器的确切示例,该触发器处理触发器操作INSERT,UPDATE和DELETE的所有(3)三个条件.我终于找到了一行文字,其中谈到了当发生DELETE或UPDATE时,公共DELETED表将包含这两个动作的记录.基于该信息,我创建了一个小的Action例程,用于确定触发器被激活的原因.当在INSERT与UPDATE触发器上同时存在公共配置和特定操作时,有时需要此类型的接口.在这些情况下,为UPDATE和INSERT创建单独的触发器将成为维护问题.(即两个触发器是否都已正确更新以进行必要的常见数据算法修复?)

为此,我想提供以下多触发事件代码片段,用于在Microsoft SQL Server的一个触发器中处理INSERT,UPDATE,DELETE.

CREATE TRIGGER [dbo].[INSUPDDEL_MyDataTable]
ON [dbo].[MyDataTable] FOR INSERT, UPDATE, DELETE
AS 

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with caller queries SELECT statements.
-- If an update/insert/delete occurs on the main table, the number of records affected
-- should only be based on that table and not what records the triggers may/may not
-- select.
SET NOCOUNT ON;

--
-- Variables Needed for this Trigger
-- 
DECLARE @PACKLIST_ID varchar(15)
DECLARE @LINE_NO smallint
DECLARE @SHIPPED_QTY decimal(14,4)
DECLARE @CUST_ORDER_ID varchar(15)
--
-- Determine if this is an INSERT,UPDATE, or DELETE Action
-- 
DECLARE @Action as char(1)
DECLARE @Count as int
SET @Action = 'I' -- Set Action to 'I'nsert by default.
SELECT @Count = COUNT(*) FROM DELETED
if @Count > 0
    BEGIN
        SET @Action = 'D' -- Set Action to 'D'eleted.
        SELECT @Count = COUNT(*) FROM INSERTED
        IF @Count > 0
            SET @Action = 'U' -- Set Action to 'U'pdated.
    END

if @Action = 'D'
    -- This is a DELETE Record Action
    --
    BEGIN
        SELECT @PACKLIST_ID =[PACKLIST_ID]
                    ,@LINE_NO = [LINE_NO]
        FROM DELETED

        DELETE [dbo].[MyDataTable]
        WHERE [PACKLIST_ID]=@PACKLIST_ID AND [LINE_NO]=@LINE_NO
    END
 Else
    BEGIN
            --
            -- Table INSERTED is common to both the INSERT, UPDATE trigger
            --
            SELECT @PACKLIST_ID =[PACKLIST_ID]
                ,@LINE_NO = [LINE_NO]
                ,@SHIPPED_QTY =[SHIPPED_QTY]
                ,@CUST_ORDER_ID = [CUST_ORDER_ID]
            FROM INSERTED 

         if @Action = 'I'
            -- This is an Insert Record Action
            --
            BEGIN
                INSERT INTO [MyChildTable]
                    (([PACKLIST_ID]
                    ,[LINE_NO]
                    ,[STATUS]
                VALUES
                    (@PACKLIST_ID
                    ,@LINE_NO
                    ,'New Record'
                    )
            END
        else
            -- This is an Update Record Action
            --
            BEGIN
                UPDATE [MyChildTable]
                    SET [PACKLIST_ID] = @PACKLIST_ID
                          ,[LINE_NO] = @LINE_NO
                          ,[STATUS]='Update Record'
                WHERE [PACKLIST_ID]=@PACKLIST_ID AND [LINE_NO]=@LINE_NO
            END
    END   
Run Code Online (Sandbox Code Playgroud)


gun*_*sus 9

我相信嵌套ifs有点令人困惑,并且:

扁平比嵌套好[Python的禅]

;)

DROP TRIGGER IF EXISTS AFTER_MYTABLE

GO

CREATE TRIGGER dbo.AFTER_MYTABLE ON dbo.MYTABLE AFTER INSERT, UPDATE, DELETE 

AS BEGIN 

    --- FILL THE BEGIN/END SECTION FOR YOUR NEEDS.

    SET NOCOUNT ON;

    IF EXISTS(SELECT * FROM INSERTED)  AND EXISTS(SELECT * FROM DELETED) 
        BEGIN PRINT 'UPDATE' END 
    ELSE IF EXISTS(SELECT * FROM INSERTED)  AND NOT EXISTS(SELECT * FROM DELETED) 
        BEGIN PRINT 'INSERT' END 
    ELSE IF    EXISTS(SELECT * FROM DELETED) AND NOT EXISTS(SELECT * FROM INSERTED)
        BEGIN PRINT 'DELETED' END
    ELSE BEGIN PRINT 'NOTHING CHANGED'; RETURN; END  -- NOTHING

END
Run Code Online (Sandbox Code Playgroud)


小智 7

Declare @Type varchar(50)='';
IF EXISTS (SELECT * FROM inserted) and  EXISTS (SELECT * FROM deleted)
BEGIN
    SELECT @Type = 'UPDATE'
END
ELSE IF EXISTS(SELECT * FROM inserted)
BEGIN
    SELECT @Type = 'INSERT'
END
ElSE IF EXISTS(SELECT * FROM deleted)
BEGIN
    SELECT @Type = 'DELETE'
END
Run Code Online (Sandbox Code Playgroud)


gre*_*reg 7

虽然我也喜欢@Alex 发布的答案,但我为上面的@Graham 解决方案提供了这种变化

这仅使用 INSERTED 和 UPDATED 表中的记录存在,而不是使用 COLUMNS_UPDATED 进行第一次测试。它还为偏执的程序员提供了解脱,因为它知道已经考虑了最后一个案例......

declare @action varchar(4)
    IF EXISTS (SELECT * FROM INSERTED)
        BEGIN
            IF EXISTS (SELECT * FROM DELETED) 
                SET @action = 'U'  -- update
            ELSE
                SET @action = 'I'  --insert
        END
    ELSE IF EXISTS (SELECT * FROM DELETED)
        SET @action = 'D'  -- delete
    else 
        set @action = 'noop' --no records affected
--print @action
Run Code Online (Sandbox Code Playgroud)

您将获得 NOOP,其中包含如下语句:

update tbl1 set col1='cat' where 1=2
Run Code Online (Sandbox Code Playgroud)


小智 5

试试这个..

ALTER TRIGGER ImportacionesGS ON dbo.Compra 
    AFTER INSERT, UPDATE, DELETE
AS
BEGIN
  -- idCompra is PK
  DECLARE @vIdCompra_Ins INT,@vIdCompra_Del INT
  SELECT @vIdCompra_Ins=Inserted.idCompra FROM Inserted
  SELECT @vIdCompra_Del=Deleted.idCompra FROM Deleted
  IF (@vIdCompra_Ins IS NOT NULL AND @vIdCompra_Del IS NULL)  
  Begin
     -- Todo Insert
  End
  IF (@vIdCompra_Ins IS NOT NULL AND @vIdCompra_Del IS NOT NULL)
  Begin
     -- Todo Update
  End
  IF (@vIdCompra_Ins IS NULL AND @vIdCompra_Del IS NOT NULL)
  Begin
     -- Todo Delete
  End
END
Run Code Online (Sandbox Code Playgroud)


Dav*_*vid 5

DECLARE @ActionType CHAR(6);
SELECT  @ActionType = COALESCE(CASE WHEN EXISTS(SELECT * FROM INSERTED)
                                     AND EXISTS(SELECT * FROM DELETED)  THEN 'UPDATE' END,
                               CASE WHEN EXISTS(SELECT * FROM DELETED)  THEN 'DELETE' END,
                               CASE WHEN EXISTS(SELECT * FROM INSERTED) THEN 'INSERT' END);
PRINT   @ActionType;
Run Code Online (Sandbox Code Playgroud)