0

使用插入和删除表的一个警告是它们都可以是空的。还有其他我应该注意的catchya吗?例如,插入的表是否可以包含新记录和更新记录?

我依靠这个逻辑来检测触发器中的动作:

IF EXISTS(SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted) SET @operation = 'U'
IF EXISTS(SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted) SET @operation = 'I'
IF NOT EXISTS(SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted) SET @operation = 'D'
IF NOT EXISTS(SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted) SET @operation = 'X'

编辑:

这是我对审计跟踪问题的解决方案。它已经在一个插入、虚假更新、真实更新和删除的 MERGE 语句上进行了测试。

ALTER TRIGGER [dbo].[LogInsertEditDelete]
ON [dbo].[<TableToAudit>]
   AFTER INSERT,DELETE,UPDATE
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

--You will need to change @table to match the table to be audited
DECLARE @table VARCHAR(50)
SELECT @table = '<TableToAudit>'

-- date and user
DECLARE @updatedBy VARCHAR(50),
        @timestamp DateTime
SELECT @updatedBy = SYSTEM_USER,
       @timestamp = GETDATE()

-- Action, U = update, I = insert, D = delete
DECLARE @insertedCount int, 
        @deletedCount int
SET @insertedCount = (SELECT COUNT(*) FROM inserted)
SET @deletedCount = (SELECT COUNT(*) FROM deleted)

-- handle no action
IF @insertedCount = 0 AND @deletedCount = 0 RETURN  

-- handle update
IF @insertedCount <> 0 AND @deletedCount <> 0
BEGIN
    INSERT Audit (Type, TableName, UpdateDate, UpdatedBy, PK1)
    SELECT
        'U', 
        @table,
        @timestamp,
        @updatedBy,
        CONVERT(VARCHAR(255), i.Id)
    FROM
        (SELECT Id, BINARY_CHECKSUM(*) Version FROM inserted) i
        INNER JOIN
        (SELECT Id, BINARY_CHECKSUM(*) Version FROM deleted) d
        ON i.Id = d.Id
    WHERE
        i.Version <> d.Version  

    RETURN      
END

-- handle deletes and inserts
INSERT Audit (Type, TableName, UpdateDate, UpdatedBy, PK1)
SELECT          
    CASE 
        WHEN i.Id IS NOT NULL AND d.Id IS NULL THEN 'I'
        WHEN i.Id IS NULL AND d.Id IS NOT NULL THEN 'D'
    END,
    @table,
    @timestamp,
    @updatedBy,
    CONVERT(VARCHAR(255), COALESCE(i.Id, d.Id))
FROM inserted i 
        FULL OUTER JOIN
     deleted d 
        ON i.Id = d.Id
WHERE i.Id IS NULL OR
      d.Id IS NULL

END

此解决方案不是通用的,因为需要为每个表拼出主键。

4

2 回答 2

1

所有 4 种情况都是可能的。值得注意的是,在更新的情况下为“both”,在 DML 语句未修改任何行的情况下为“none”。

EXISTS可以比使用查询更便宜地检测到最后一个条件:

if @@ROWCOUNT = 0
    return

您可以稍微调整一下EXIST-check 结构,以便每个表只查询一次以提高效率。

于 2012-09-05T19:03:11.520 回答
1

发表评论后,我对 MERGE 中插入和删除的表中的内容感到好奇。这是一个例子:

create table #test (test1 int identity not null, test2 varchar(34) null)


Insert into #test (test2)
values('test'), ('test2')

select * from #test


declare @output table(test1I int, test1D int, test2I varchar (34), test2D varchar (34))


MERGE #test AS target
USING (SELECT test1, test2 from #test ) AS source (test1, test2)
ON (target.test1 = source.test1)
WHEN MATCHED AND target.test1 = 1
    THEN UPDATE SET target.test2 = 'test3'
WHEN  MATCHED 
    THEN DELETE

OUTPUT inserted.test1, deleted.test1,  inserted.test2, deleted.test2 into @output ;

select 'Inserted/deleted contents', * from @output
select * from #test

Drop table #test

如果您正在执行插入或更新,则会发生类似的事情。

如果您需要了解每条记录,您可能希望使用连接和案例语句来确定每条记录的状态,而不是使用标量变量。请记住,触发器一次对插入/更新/删除的整个记录​​集进行操作,而不是一次记录一条记录。所以使用标量变量通常是你没有正确做事的线索。如果您给我们提供更多有关触发器将要做什么的示例,那么帮助您解决问题会更容易,因为当前的方法似乎无法涵盖所有​​记录。

根据您上面的评论,也许这会给您一些关于在触发器中尝试什么的想法:

Insert dbo.Audittable (Id, NewField1Value, OldField1Value, ActionTaken, ActionDate, ActionUser)
select coalesce(inserted.id, deleted.id) as Id, inserted.field1 as newField1value, deleted.field1 as oldField1value ,
case when inserted.id is not null and deleted.id is not null then 'Update'
when inserted.id is not null and deleted.id is  null then 'Insert'
when inserted.id is null and deleted.id is not null then 'Delete'
End as ActionTaken
, getdate() as ActionDate
, system_user as ActionUser
from inserted
full outer join deleted on inserted.id = deleted.id

测试触发器时,您至少需要以下测试用例:

  • 单条记录插入
  • 单条记录删除
  • 单条记录更新
  • 多条记录插入
  • 多条记录删除
  • 多条记录更新
  • 插入和删除的多条记录合并
  • 进行更新和删除的多条记录合并
  • 插入和更新的多条记录合并

您可能需要更多,具体取决于触发器将要执行的所有操作。

于 2012-09-05T19:36:54.030 回答