【问题标题】:Insert Update trigger how to determine if insert or update插入更新触发器如何确定是插入还是更新
【发布时间】:2010-10-18 23:46:59
【问题描述】:

我需要在表 A 上编写一个插入更新触发器,它将删除表 B 中的所有行,其中一列(比如 Desc)的值类似于表 A 的列(比如 Col1)中插入/更新的值。我将如何编写它以便我可以处理更新和插入情况。我如何确定触发器是针对更新还是插入执行的。

【问题讨论】:

    标签: sql-server tsql triggers


    【解决方案1】:

    触发器具有特殊的INSERTEDDELETED 表来跟踪“之前”和“之后”数据。所以你可以使用IF EXISTS (SELECT * FROM DELETED) 之类的东西来检测更新。 DELETED 更新时只有行,但INSERTED 中始终有行。

    CREATE TRIGGER 中查找“已插入”。

    编辑,2011 年 11 月 23 日

    评论后,此答案仅适用于INSERTEDUPDATED 触发器。
    显然,DELETE 触发器不能像我上面所说的那样具有“INSERTED 中的始终行”

    【讨论】:

    • 查看下面@MikeTeeVee 的答案以获得完整答案。这个不完整。
    • @LorenzMeyer 原始问题不需要那个。我也有 EXISTS (SELECT * FROM DELETED)。不知道为什么你认为它不完整...
    • @LorenzMeyer 也可能指的是语句“更新时您只有 DELETED 中的行,但 INSERTED 中有 总是 行。" 这并不总是为真,因为有时会调用更新/插入触发器并且 INSERTED 为空。在我的回答中,我解释了这可能是由谓词消除任何数据更改引起的。在这种情况下,仍然会为 DML 尝试调用触发器,但 DELETED 和 INSERTED 表是空的。这是因为当您想要记录每个 DML 尝试时,SQL 仍会考虑时间(即使它们没有更改任何数据)。
    【解决方案2】:

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

    为此,我想提供以下多触发事件代码 sn-p,用于在 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   
    

    【讨论】:

      【解决方案3】:
      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
      

      【讨论】:

      • 我也喜欢写 SELECT 1 FROM INSERTED 因为我认为它更清楚地表明意图,但如果这在这种情况下有所不同,我会对 MSSQL 程序员感到失望......
      • IF EXISTS(SELECT * ...) 和 IF EXISTS(SELECT 1) ... 具有完全相同的性能。该行根本不被读取或提取。事实上你也可以使用 IF EXISTS(SELECT 1/0 ...) 它仍然可以工作并且不会导致除以零错误。
      • 我正在为插入、更新和删除创建单独的触发器。现在很高兴知道它们可以组合!
      • 如果有人将查询写入 INSERT 和 DELETE 两个不同的行(在同一脚本中插入新行并删除另一行),是否有可能以上述方式设置的触发器实际上会识别由于 INSERTED/DELETED sql-tables 中有数据,因此作为 UPDATE(即使意图实际上不是更新)?
      【解决方案4】:

      这可能是一种更快的方法:

      DECLARE @action char(1)
      
      IF COLUMNS_UPDATED() > 0 -- insert or update
      BEGIN
          IF EXISTS (SELECT * FROM DELETED) -- update
              SET @action = 'U'
          ELSE
              SET @action = 'I'
          END
      ELSE -- delete
          SET @action = 'D'
      

      【讨论】:

      • 这种方式不适用于具有大量列的表,因为 columns_updated() 返回一个巨大的 varbinary。所以 "> 0" 失败,因为 0 默认为内部存储的数字,远小于从 columns_updated() 返回的值
      【解决方案5】:

      所提供的两种解决方案的一个潜在问题是,根据它们的编写方式,更新查询可能会更新零个记录,而插入查询可能会插入零个记录。在这些情况下,Inserted 和 Deleted 记录集将为空。在许多情况下,如果 Inserted 和 Deleted 记录集都是空的,您可能只想退出触发器而不做任何事情。

      【讨论】:

        【解决方案6】:

        我在 Grahams 中发现了一个小错误,否则很酷的解决方案:

        应该是 IF COLUMNS_UPDATED() > 0 -- 插入或更新
        而不是 > 0 可能是因为最高位被解释为有符号整数符号位......(?)。 所以总的来说:

        DECLARE @action CHAR(8)  
        IF COLUMNS_UPDATED() <> 0 -- delete or update?
        BEGIN     
          IF EXISTS (SELECT * FROM deleted) -- updated cols + old rows means action=update       
            SET @action = 'UPDATE'     
          ELSE
            SET @action = 'INSERT' -- updated columns and nothing deleted means action=insert
        END 
        ELSE -- delete     
        BEGIN
          SET @action = 'DELETE'
        END
        

        【讨论】:

          【解决方案7】:

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

          为了安全起见:

          --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)
          

          特别感谢@KenDog 和@Net_Prog 的回答。
          我根据他们的脚本构建了这个。

          【讨论】:

          • 这个是奖品,处理不存在已删除。干得好!
          • 我们也可能有一个不影响行(甚至是 INSERT)的更新。
          • @AndrewWolfe ?你在说什么?该问题明确指出“我需要在表 A 上编写插入、更新触发器”。与 DELETE 触发器无关。
          • @ypercubeᵀᴹ 抱歉,我大约 80% 的触发器涵盖了所有三个时间。
          【解决方案8】:

          在第一种情况下,我认为您的表有 IDENTITY 列

          CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
          FOR INSERT, UPDATE, DELETE
          AS
          IF @@ROWCOUNT = 0 return
          SET NOCOUNT ON;
          DECLARE @action nvarchar(10)
          SELECT @action = CASE WHEN COUNT(i.Id) > COUNT(d.Id) THEN 'inserted'
                                WHEN COUNT(i.Id) < COUNT(d.Id) THEN 'deleted' ELSE 'updated' END
          FROM inserted i FULL JOIN deleted d ON i.Id = d.Id
          

          在第二种情况下不需要使用 IDENTITTY 列

          CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
          FOR INSERT, UPDATE, DELETE
          AS
          IF @@ROWCOUNT = 0 return
          SET NOCOUNT ON;
          DECLARE @action nvarchar(10),
                  @insCount int = (SELECT COUNT(*) FROM inserted),
                  @delCount int = (SELECT COUNT(*) FROM deleted)
          SELECT @action = CASE WHEN @insCount > @delCount THEN 'inserted'
                                WHEN @insCount < @delCount THEN 'deleted' ELSE 'updated' END
          

          【讨论】:

          【解决方案9】:

          快速解决MySQL

          顺便说一句:我正在使用 MySQL PDO。

          (1) 在自动增量表中,每次脚本首先运行时,只需从增量列中获取最大值(我的列名 = id):

          $select = "
              SELECT  MAX(id) AS maxid
              FROM    [tablename]
              LIMIT   1
          ";
          

          (2) 像往常一样运行 MySQL 查询,并将结果转换为整数,例如:

          $iMaxId = (int) $result[0]->maxid;
          

          (3) 在“INSERT INTO ... ON DUPLICATE KEY UPDATE”查询之后,获取最后插入的 id 您喜欢的方式,例如:

          $iLastInsertId = (int) $db->lastInsertId();
          

          (4)比较和反应:如果lastInsertId高于表中的最高值,那可能是INSERT,对吧?反之亦然。

          if ($iLastInsertId > $iMaxObjektId) {
              // IT'S AN INSERT
          }
          else {
              // IT'S AN UPDATE
          }
          

          我知道它很快而且可能很脏。这是一个旧帖子。但是,嘿,我一直在寻找解决方案,也许有人发现我的方法还是有用的。万事如意!

          【讨论】:

            【解决方案10】:

            这对我有用:

            declare @action_type int;
            select @action_type = case
                                   when i.id is not null and d.id is     null then 1 -- insert
                                   when i.id is not null and d.id is not null then 2 -- update
                                   when i.id is     null and d.id is not null then 3 -- delete
                                 end
              from      inserted i
              full join deleted  d on d.id = i.id
            

            由于并非所有列都可以一次更新,因此您可以通过以下方式检查特定列是否正在更新:

            IF UPDATE([column_name])
            

            【讨论】:

            • 使用此解决方案的挑战是您必须知道列名。其他一些设计使得您可以从 sn-p 库中复制粘贴。小点,但考虑到所有因素,通用解决方案优于特定案例解决方案。恕我直言。
            【解决方案11】:

            简单的方法

            CREATE TRIGGER [dbo].[WO_EXECUTION_TRIU_RECORD] ON [dbo].[WO_EXECUTION]
            WITH EXECUTE AS CALLER
            FOR INSERT, UPDATE
            AS
            BEGIN  
            
              select @vars = [column] from inserted 
              IF UPDATE([column]) BEGIN
                -- do update action base on @vars 
              END ELSE BEGIN
                -- do insert action base on @vars 
              END
            
            END 
            

            【讨论】:

            • 根据我的 SSMS IDE,您在 IF BEGIN - END ELSE BEGIN - END 块中包装逻辑的方式不正确。
            【解决方案12】:
            DECLARE @INSERTEDCOUNT INT,
                    @DELETEDCOUNT INT
            
            SELECT @INSERTEDCOUNT = COUNT([YourColumnName]) FROM inserted
            
            SELECT @DELETEDCOUNT = COUNT([YourColumnName]) FROM deleted
            

            如果它的更新

             @INSERTEDCOUNT = 1
             @DELETEDCOUNT = 1
            

            如果它的插入

             @INSERTEDCOUNT = 1
             @DELETEDCOUNT = 0
            

            【讨论】:

              【解决方案13】:
              declare @insCount int
              declare @delCount int
              declare @action char(1)
              
              select @insCount = count(*) from INSERTED
              select @delCount = count(*) from DELETED
              
                  if(@insCount > 0 or @delCount > 0)--if something was actually affected, otherwise do nothing
                  Begin
                      if(@insCount = @delCount)
                          set @action = 'U'--is update
                      else if(@insCount > 0)
                          set @action = 'I' --is insert
                      else
                          set @action = 'D' --is delete
              
                      --do stuff here
                  End
              

              【讨论】:

              • 出于性能原因,我不会使用 COUNT(*) - 它需要扫描整个表。我会改为使用 IF EXISTS(SELECT * FROM INSERTED) 设置一个标志,对于 DELETED 也是如此。我知道通常只有几行受到影响,但为什么要减慢系统速度。
              • 我正要发布一些非常相似的解决方案。它有点罗嗦,但非常可读。公平的权衡。我也喜欢上面的 Grahms 解决方案。
              【解决方案14】:

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

              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;
              

              【讨论】:

              • 这个错误检测到不插入或不更新的语句。
              【解决方案15】:

              我已经使用了很长时间的 exists (select * from inserted/deleted) 查询,但是对于空 CRUD 操作(当 inserteddeleted 表中没有记录时)仍然不够。所以在稍微研究了这个话题之后,我找到了更精确的解决方案:

              declare
                  @columns_count int = ?? -- number of columns in the table,
                  @columns_updated_count int = 0
              
              -- this is kind of long way to get number of actually updated columns
              -- from columns_updated() mask, it's better to create helper table
              -- or at least function in the real system
              with cte_columns as (
                  select @columns_count as n
                  union all
                  select n - 1 from cte_columns where n > 1
              ), cte_bitmasks as (
                  select
                      n,
                      (n - 1) / 8 + 1 as byte_number,
                      power(2, (n - 1) % 8) as bit_mask
                  from cte_columns
              )
              select
                  @columns_updated_count = count(*)
              from cte_bitmasks as c
              where
                  convert(varbinary(1), substring(@columns_updated_mask, c.byte_number, 1)) & c.bit_mask > 0
              
              -- actual check
              if exists (select * from inserted)
                  if exists (select * from deleted)
                      select @operation = 'U'
                  else
                      select @operation = 'I'
              else if exists (select * from deleted)
                  select @operation = 'D'
              else if @columns_updated_count = @columns_count
                  select @operation = 'I'
              else if @columns_updated_count > 0
                  select @operation = 'U'
              else
                  select @operation = 'D'
              

              也可以使用columns_updated() &amp; power(2, column_id - 1) &gt; 0 来查看列是否更新,但是对于具有大量列的表并不安全。我使用了一种有点复杂的计算方法(请参阅下面的有用文章)。

              此外,这种方法仍然会错误地将某些更新分类为插入(如果表中的每一列都受到更新的影响),并且可能会将仅插入默认值的插入分类为删除,但这些是非常罕见的操作(至少在我的系统中它们是)。 除此之外,我目前不知道如何改进此解决方案。

              【讨论】:

                【解决方案16】:

                我喜欢“计算机科学优雅”的解决方案。我的解决方案在这里点击 [inserted] 和 [deleted] 伪表一次以获取它们的状态并将结果放入位映射变量中。然后,可以通过有效的二进制评估在整个触发器中轻松测试 INSERT、UPDATE 和 DELETE 的每个可能组合(不太可能的 INSERT 或 DELETE 组合除外)。

                它确实假设如果没有修改任何行,那么 DML 语句是什么并不重要(这应该满足绝大多数情况)。因此,虽然它不像 Roman Pekar 的解决方案那样完整,但它更有效。

                使用这种方法,我们可以为每个表创建一个“FOR INSERT、UPDATE、DELETE”触发器,从而使我们 A) 完全控制操作顺序和 b) 每个适用于多操作的操作一个代码实现。 (显然,每种实施模型都有其优点和缺点;您需要单独评估您的系统,以了解哪些是最有效的。)

                请注意,“exists (select * from «inserted/deleted»)”语句非常有效,因为没有磁盘访问 (https://social.msdn.microsoft.com/Forums/en-US/01744422-23fe-42f6-9ab0-a255cdf2904a)。

                use tempdb
                ;
                create table dbo.TrigAction (asdf int)
                ;
                GO
                create trigger dbo.TrigActionTrig
                on dbo.TrigAction
                for INSERT, UPDATE, DELETE
                as
                declare @Action tinyint
                ;
                -- Create bit map in @Action using bitwise OR "|"
                set @Action = (-- 1: INSERT, 2: DELETE, 3: UPDATE, 0: No Rows Modified 
                  (select case when exists (select * from inserted) then 1 else 0 end)
                | (select case when exists (select * from deleted ) then 2 else 0 end))
                ;
                -- 21 <- Binary bit values
                -- 00 -> No Rows Modified
                -- 01 -> INSERT -- INSERT and UPDATE have the 1 bit set
                -- 11 -> UPDATE <
                -- 10 -> DELETE -- DELETE and UPDATE have the 2 bit set
                
                raiserror(N'@Action = %d', 10, 1, @Action) with nowait
                ;
                if (@Action = 0) raiserror(N'No Data Modified.', 10, 1) with nowait
                ;
                -- do things for INSERT only
                if (@Action = 1) raiserror(N'Only for INSERT.', 10, 1) with nowait
                ;
                -- do things for UPDATE only
                if (@Action = 3) raiserror(N'Only for UPDATE.', 10, 1) with nowait
                ;
                -- do things for DELETE only
                if (@Action = 2) raiserror(N'Only for DELETE.', 10, 1) with nowait
                ;
                -- do things for INSERT or UPDATE
                if (@Action & 1 = 1) raiserror(N'For INSERT or UPDATE.', 10, 1) with nowait
                ;
                -- do things for UPDATE or DELETE
                if (@Action & 2 = 2) raiserror(N'For UPDATE or DELETE.', 10, 1) with nowait
                ;
                -- do things for INSERT or DELETE (unlikely)
                if (@Action in (1,2)) raiserror(N'For INSERT or DELETE.', 10, 1) with nowait
                -- if already "return" on @Action = 0, then use @Action < 3 for INSERT or DELETE
                ;
                GO
                
                set nocount on;
                
                raiserror(N'
                INSERT 0...', 10, 1) with nowait;
                insert dbo.TrigAction (asdf) select top 0 object_id from sys.objects;
                
                raiserror(N'
                INSERT 3...', 10, 1) with nowait;
                insert dbo.TrigAction (asdf) select top 3 object_id from sys.objects;
                
                raiserror(N'
                UPDATE 0...', 10, 1) with nowait;
                update t set asdf = asdf /1 from dbo.TrigAction t where asdf <> asdf;
                
                raiserror(N'
                UPDATE 3...', 10, 1) with nowait;
                update t set asdf = asdf /1 from dbo.TrigAction t;
                
                raiserror(N'
                DELETE 0...', 10, 1) with nowait;
                delete t from dbo.TrigAction t where asdf < 0;
                
                raiserror(N'
                DELETE 3...', 10, 1) with nowait;
                delete t from dbo.TrigAction t;
                GO
                
                drop table dbo.TrigAction
                ;
                GO
                

                【讨论】:

                • 感谢这个适合我的解决方案。您会推荐一种方法来更新更新/插入行的 LastUpdated 列吗?您是否还会推荐一种将已删除行的 ID 存储在另一个表上的方法(可能是组合键)?
                【解决方案17】:

                我认为嵌套的 if 有点令人困惑,并且:

                扁平胜于嵌套[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
                

                【讨论】:

                  【解决方案18】:

                  试试这个..

                  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
                  

                  【讨论】:

                    【解决方案19】:
                    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
                    

                    【讨论】:

                      【解决方案20】:

                      虽然我也喜欢@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
                      

                      你会得到 NOOP 的语句,如下所示:

                      update tbl1 set col1='cat' where 1=2
                      

                      【讨论】:

                      • 第一个END好像缩进不对! (导致质疑第一个 BEGIN 关闭的位置)
                      • else if 和 final else 包含单个语句。因为 IF/Else 是一个单一的语句,所以 begin 和 end 真的是不必要的。我确实纠正了缩进。感谢您的帮助。
                      【解决方案21】:
                      declare @result as smallint
                      declare @delete as smallint = 2
                      declare @insert as smallint = 4
                      declare @update as smallint = 6
                      SELECT @result = POWER(2*(SELECT count(*) from deleted),1) + POWER(2*(SELECT 
                           count(*) from inserted),2)
                      
                      if (@result & @update = @update) 
                      BEGIN
                        print 'update'
                        SET @result=0
                      END
                      if (@result & @delete = @delete)
                        print 'delete'
                      if (@result & @insert = @insert)
                        print 'insert'
                      

                      【讨论】:

                        【解决方案22】:

                        我这样做:

                        select isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)
                        

                        1 -> 插入

                        2 -> 删除

                        3 -> 更新

                        set @i = isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)
                        --select @i
                        
                        declare @action varchar(1) = case @i when 1 then 'I' when 2 then 'D' when 3 then 'U' end
                        --select @action
                        
                        
                        select @action c1,* from inserted t1 where @i in (1,3) union all
                        select @action c1,* from deleted t1 where @i in (2)
                        

                        【讨论】:

                          【解决方案23】:
                          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;
                          

                          【讨论】:

                            猜你喜欢
                            • 2011-04-09
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2015-11-06
                            • 2014-12-29
                            • 2016-10-13
                            • 2012-03-27
                            相关资源
                            最近更新 更多