Sql server 处理审核/历史记录更新触发器中的空值

Sql server 处理审核/历史记录更新触发器中的空值,sql-server,tsql,triggers,null,sql-server-2008-r2,Sql Server,Tsql,Triggers,Null,Sql Server 2008 R2,假设我有两个表,一个“实时”表和一个历史表。活动表如下所示: CREATE TABLE dbo.LiveTable ( LiveTableId INT IDENTITY(1,1) NOT NULL PRIMARY KEY, SomeVarChar VARCHAR(20) NOT NULL DEFAULT '', SomeForeignId INT NULL, OtherForeingId INT NULL, ChangeBy VARCHAR(128) NO

假设我有两个表,一个“实时”表和一个历史表。活动表如下所示:

CREATE TABLE dbo.LiveTable (
    LiveTableId INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    SomeVarChar VARCHAR(20) NOT NULL DEFAULT '',
    SomeForeignId INT NULL,
    OtherForeingId INT NULL,
    ChangeBy VARCHAR(128) NOT NULL,
    ChangeTime DATETIME NOT NULL DEFAULT GETDATE()
)
CREATE TRIGGER dbo.trgLiveTableUpdate ON dbo.LiveTable FOR UPDATE
AS
INSERT INTO dbo.LiveTableHistory (
    LiveTableId,
    SomeVarChar,
    SomeForeignId,
    OtherForeignId,
    ChangeBy,
    ChangeTime
)
SELECT 
    d.LiveTableId,
    d.SomeVarChar,
    d.SomeForeignId,
    d.OtherForeignId,
    d.ChangeBy,
    d.ChangeTime
FROM DELETED d
JOIN INSERTED i ON d.LiveTableId = i.LiveTableId
WHERE d.SomeVarChar <> i.SomeVarChar
OR d.SomeForeignId <> i.SomeForeignId   //<--- I don't think this works
OR d.OtherForeignId <> i.OtherForeignId //<--- this either
历史记录表看起来是一样的,只是它有自己的主键和在别处使用的
IsDelete
列。当用户更新
LiveTable
中的一行时,我希望将该行的先前值记录在历史记录表中。当然,使用
UPDATE
触发器就足够简单了。但是我刚刚确定我的一些更新没有触发历史表插入,我相信这是由于允许空值的字段造成的。我的触发器看起来像这样:

CREATE TABLE dbo.LiveTable (
    LiveTableId INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    SomeVarChar VARCHAR(20) NOT NULL DEFAULT '',
    SomeForeignId INT NULL,
    OtherForeingId INT NULL,
    ChangeBy VARCHAR(128) NOT NULL,
    ChangeTime DATETIME NOT NULL DEFAULT GETDATE()
)
CREATE TRIGGER dbo.trgLiveTableUpdate ON dbo.LiveTable FOR UPDATE
AS
INSERT INTO dbo.LiveTableHistory (
    LiveTableId,
    SomeVarChar,
    SomeForeignId,
    OtherForeignId,
    ChangeBy,
    ChangeTime
)
SELECT 
    d.LiveTableId,
    d.SomeVarChar,
    d.SomeForeignId,
    d.OtherForeignId,
    d.ChangeBy,
    d.ChangeTime
FROM DELETED d
JOIN INSERTED i ON d.LiveTableId = i.LiveTableId
WHERE d.SomeVarChar <> i.SomeVarChar
OR d.SomeForeignId <> i.SomeForeignId   //<--- I don't think this works
OR d.OtherForeignId <> i.OtherForeignId //<--- this either
在dbo.LiveTable上创建触发器dbo.trgLiveTableUpdate以进行更新
像
插入到dbo.LiveTableHistory中(
LiveTableId,
萨默瓦查尔,
有些异国情调,
另类的,
换衣服,
转换时间
)
选择
d、 LiveTableId,
d、 萨默瓦查尔,
d、 有些异国情调,
d、 另类的,
d、 换衣服,
d、 转换时间
从已删除的d
在d.LiveTableId=i.LiveTableId上连接插入的i
其中d.SomeVarChar i.SomeVarChar
或者d.someforeignd i.someforeignd/
其中d.SomeVarChar i.SomeVarChar
或者ISNULL(d.someforeigned,-987654)ISNULL(i.someforeigned,-987654)
或者ISNULL(d.otherforeignd,-987654)ISNULL(i.otherforeignd,-987654)
*请注意,-987654只是ID列中一些未使用的数字。如果它链接回标识列-1就足够了。

其中d.SomeVarChar i.SomeVarChar
或者ISNULL(d.someforeigned,-987654)ISNULL(i.someforeigned,-987654)
或者ISNULL(d.otherforeignd,-987654)ISNULL(i.otherforeignd,-987654)

*请注意,-987654只是ID列中一些未使用的数字。如果它链接回一个标识列-1就足够了。

您还可以找到异常,这些异常为您提供了要记录的密钥

select 
    d.LiveTableId,
    d.SomeVarChar,
    d.SomeForeignId,
    d.OtherForeignId,
    d.ChangeBy,
    d.ChangeTime
from DELETED d
join
(
select LiveTableId, SomeVarChar, SomeForeignId, OtherForeignId from INSERTED
EXCEPT 
select LiveTableId, SomeVarChar, SomeForeignId, OtherForeignId from DELETED
) e on e.LiveTableId = d.LiveTableId

您还可以找到异常,这些异常为您提供了要记录的密钥

select 
    d.LiveTableId,
    d.SomeVarChar,
    d.SomeForeignId,
    d.OtherForeignId,
    d.ChangeBy,
    d.ChangeTime
from DELETED d
join
(
select LiveTableId, SomeVarChar, SomeForeignId, OtherForeignId from INSERTED
EXCEPT 
select LiveTableId, SomeVarChar, SomeForeignId, OtherForeignId from DELETED
) e on e.LiveTableId = d.LiveTableId

不是问题,但如果没有更改,请考虑停止更新。 如果没有更改,则可以阻止更新

update live table  
set SomeVarChar  = 'a' 
where SomeVarChar is null or SomeVarChar  != 'a'
如果一次只有一条记录,则不是一个因素。
但是当99%的值已经是“A”时,全局更新SomeVarChar='A'是大量的非更新

是的,把扳机修好


如果你有性能问题,需要考虑的事情。

不是问题,而是考虑如果没有更改,停止更新。 如果没有更改,则可以阻止更新

update live table  
set SomeVarChar  = 'a' 
where SomeVarChar is null or SomeVarChar  != 'a'
如果一次只有一条记录,则不是一个因素。
但是当99%的值已经是“A”时,全局更新SomeVarChar='A'是大量的非更新

是的,把扳机修好


如果你有表演问题的话,我想所有这些答案都是可行的,我是一个“李察”,也就是“赛维基”的答案。我想所有这些答案都是可行的,我是李察的一个傻瓜,也不是网络Wiki的回答。我不确定我理解…WHERE条款。(或除非在接受的答案中)阻止触发的插入发生。您是说即使插入没有发生,执行所有这些更新的触发器也会导致性能问题吗?应该是!=“a”。我不确定我是否理解where子句(或除接受答案中的外)阻止触发的插入发生。您是说即使插入没有发生,执行所有这些更新的触发器也会导致性能问题吗?应该是!=“a”。