如果行更改除一列之外,则使用触发器将记录插入另一个表

时间:2013-10-08 10:14:31

标签: sql sql-server sql-server-2008 triggers

案例

我有两个包含以下结构的表(我删除了其他34个与问题无关的列)

Table1
------
Id
LastAccessed
Data1
Data2

Table1_History
------
_Id
Action
Id
LastAccessed
Data1
Data2

每次用户阅读记录(使用特定程序)时,LastAccessed时间戳都会发生变化。

我为Table1添加了一个触发器,如果​​Data1Data2(或者我的情况下任何其他列更改),它会将记录复制到历史记录表中;但是,如果LastAccessed更改,我不想要副本或记录。

这是我的触发器

CREATE TRIGGER [TRIGGER!] 
   ON  TABLE1
   AFTER UPDATE, DELETE
AS 
BEGIN
    SET NOCOUNT ON;
    IF NOT UPDATE([LastAccessed]) BEGIN
        IF EXISTS(SELECT * FROM inserted) BEGIN
            INSERT INTO [Table1_Hist](
                Action, Id, LastAccessed, Data1, Data2
            ) SELECT 
                'EDIT', Id, LastAccessed, Data1, Data2
            FROM deleted
        END ELSE BEGIN
            INSERT INTO [Table1_Hist](
                Action, Id, LastAccessed, Data1, Data2
            ) SELECT 
                'DELETE', Id, LastAccessed, Data1, Data2
            FROM deleted
        END
    END
END

如果LastAccessed和Data1都发生了变化(我想要),则此触发器不会复制行。要解决此问题,我可以将IF语句更改为

IF UPDATE(Id) OR UPDATE(Data1) OR UPDATE(Data2) ... BEGIN

在这种情况下,它将按预期工作

问题: 由于我的表中有34列,因此在IF语句中指定每一列并不容易。 有没有更简单的方法呢?

2 个答案:

答案 0 :(得分:3)

希望有人有一个比这更优雅的答案,但最糟糕的情况是你可以通过一个简单的查询为所有34列生成丑陋的IF语句:

SELECT CASE WHEN column_id = 1 THEN 'IF ' ELSE 'OR ' END + 'UPDATE(' + name + ')' 
    FROM sys.columns 
    WHERE object_id = OBJECT_ID(N'[dbo].[Table1]') 
        AND name <> 'LastUpdated'
    ORDER BY column_id

然后你可以为IF语句剪切并粘贴结果......不是一个优雅的解决方案,但它比手动输入更快。

答案 1 :(得分:0)

CREATE TRIGGER [TRIGGER!] 
   ON  TABLE1
   AFTER UPDATE
AS 
BEGIN

INSERT INTO Table1_Hist (
Action
Id
LastAccessed
Data1
Data2
)
SELECT 'UPDATE',d.ID,d.LastAccessed,d.Data1,d.Data2, etc., etc.
FROM DELETED d
INNER JOIN INSERTED i ON d.id = i.id
WHERE 
COALESCE(d.data1,'') <> COALESCE(i.data1,'') OR
COALESCE(d.data2,'') <> COALESCE(i.data2,'') OR
<repeat for every attribute EXCEPT LastAccessed>
END

这也适用于多行的插入或更新,而您的方法可能会插入数据实际上没有更改的行。

此外,您希望具有单独的UPDATE和DELETE触发器,因为在实际DELETE的情况下,您的查询应该只从DELETED转储完整的行集。