我试图在插入名为PersonalInfo的表之后编写一个触发器。 GenderID和id是表Gender和RegisterationForm的外键。
DBLog是我用来记录触发操作的表。
这就是我写的:
{{1}}
在我尝试将数据插入PersonalInfo表时执行触发器后,出现以下错误:
没有更新行
第5行中的数据未进行评估
错误来源:.Net SqlClient数据提供程序。
错误消息:无法将值NULL插入列' ActionDes', table' .dbo.DBLog&#39 ;; column不允许nulls.INSERT失败。
警告:聚合或其他SET操作消除了空值。
声明已经终止。
确实,我不允许NULL进入我的ActionDes列,但在这里我插入数据。 NULL来自何处?问题是什么?
答案 0 :(得分:3)
如果我正确理解你的触发器,对于插入表中的每一行,你要设置@variable = Max(@variable)。由于您尚未为变量赋值,因此所有变量值仍为空。
连接规则要求使用空值的连接等于空值,因此如果任何参数值为null,则@ActionDes变量以空值结束,并且当您尝试插入时,它会引发错误进入DBLog表。
答案 1 :(得分:3)
不要存储构成"假装"的字符串。插入声明。有很多方法可以插入表格,你猜测使用的格式,这是一个坏主意。
您还假设只插入了一行。这是一个严重缺陷的假设,重新编码以从inserted
表中读取多行。
在日志记录中允许NULL
。如果name
表格中NULL
字段不应为[personalInfo]
,请填写字段NOT NULL
,不要使用触发器来强制执行检查约束
不要从日志记录表中读取id
,然后递增值,将id
列设为IDENTITY
列,让数据库自行管理。您有一个竞争条件,您可以读取该值,然后其他一些进程插入一行,然后您尝试插入您的行并产生冲突。这是一个非常糟糕的做法。
CREATE [dbo].[InsertPersonalInfoTrigger] ON [dbo].[PersonalInfo]
AFTER INSERT
AS
BEGIN
INSERT INTO
DBLog (
ActionDes,
ActionTime,
ActionUser
)
SELECT
ISNULL('"' + CAST(inserted.ID AS NVARCHAR(128) + '"', 'NULL') + ' AS id, ' +
ISNULL('"' + CAST(inserted.Name AS NVARCHAR(128) + '"', 'NULL') + ' AS name, ' +
ISNULL('"' + CAST(inserted.FamilyName AS NVARCHAR(128) + '"', 'NULL') + ' AS FamilyName, ' +
ISNULL('"' + CAST(inserted.FatherName AS NVARCHAR(128) + '"', 'NULL') + ' AS FatherName, ' +
ISNULL('"' + CAST(inserted.BirthDate AS NVARCHAR(128) + '"', 'NULL') + ' AS BirthDate, ' +
ISNULL('"' + CAST(inserted.GenderID AS NVARCHAR(128) + '"', 'NULL') + ' AS GenderID, ' +
ISNULL('"' + CAST(inserted.NationalId AS NVARCHAR(128) + '"', 'NULL') + ' AS NationalID',
GETDATE(),
CURRENT_USER
FROM
inserted
-- There could be many rows in this table, don't pretend or assume there will only be one
END
GO
更好的是,为您从[PersonalInfo]
录制的每个字段分别设置日志字段。即使这意味着拥有通用DBLog
表和单独的DBLogPersonalInfo
表。
CREATE [dbo].[InsertPersonalInfoTrigger] ON [dbo].[PersonalInfo]
AFTER INSERT
AS
BEGIN
INSERT INTO
DBLog (
ActionDes,
ActionTime,
ActionUser
)
VALUES (
'INSERT INTO [dbo].[PersonalInfo]',
GETDATE(),
CURRENT_USER
);
INSERT INTO
DBLogPersonalInfo (
DBLogID,
id,
Name,
FamilyName,
FatherName,
BirthDate,
GenderID,
NationalID
)
SELECT
SCOPE_IDENTITY(), -- The latest value from the IDENTITY column of `DBlog` (as created by THIS process).
inserted.ID,
inserted.Name,
inserted.FamilyName,
inserted.FatherName,
inserted.BirthDate,
inserted.GenderID,
inserted.NationalID
FROM
inserted
-- No need for `CAST` or `ISNULL`.
-- Now you can even join DBLogPersonalInfo to PersonalInfo and compare changes (programatically)
-- Simpler, more reliable, and more flexible...
END
GO
答案 2 :(得分:1)
有几件事:
我不确定您为什么要在INSERTED上执行聚合,但我所说的我相信会解决您提到的问题。