我正在尝试创建一个“历史”表,每次更新源表上的行时都会更新该表。
这是我用来创建历史表的(SQL Server)代码:
DROP TABLE eventGroup_History
SELECT
CAST(NULL AS UNIQUEIDENTIFIER) AS NewId,
CAST(NULL AS varchar(255)) AS DoneBy,
CAST(NULL AS varchar(255)) AS Operation,
CAST(NULL AS datetime) AS DoneAt,
*
INTO
eventGroup_History
FROM
eventGroup
WHERE
1 = 0
GO
ALTER TABLE eventGroup_History
ALTER COLUMN NewId UNIQUEIDENTIFIER NOT NULL
go
ALTER TABLE eventGroup_History
ADD PRIMARY KEY (NewId)
GO
ALTER TABLE eventGroup_History
ADD CONSTRAINT DF_eventGroup_History_NewId DEFAULT NewSequentialId() FOR NewId
GO
触发器的创建方式如下:
drop trigger eventGroup_LogUpdate
go
create trigger eventGroup_LogUpdate
on dbo.eventGroup
for update
as
declare @Now as DateTime = GetDate()
set nocount on
insert into eventGroup_History
select @Now, SUser_SName(), 'update-deleted', *
from deleted
insert into eventGroup_History
select SUser_SName(), 'update-inserted', @Now, *
from inserted
go
exec sp_settriggerorder @triggername = 'eventGroup_LogUpdate', @order = 'last', @stmttype = 'update'
但是当我更新SQL Server Management Studio中的一行时,我收到一条消息:
第2行中的数据未提交。 错误来源:.Net SqlClient数据提供程序。 错误消息:从字符串转换为uniqueidentifier时转换失败。
我认为触发器试图插入SUserSName()
作为行的第一列,但那是PK NewId:
表中没有其他uniqueidentifier列。
如果我从SQL Management Studio编辑网格添加行,则添加该行而不必指定NewId值。
那么,为什么SQL Server触发器尝试使用NewId
子句中的第一项填充INSERT INTO
而不是跳过它以让正常的IDENTITY
操作提供值?
(我如何阻止这种情况发生,以便触发器工作?)
因为自动跳过仅适用于IDENTITY列 - 使用NewSequentialId()约束设置的GUID列在很多方面与IDENTITY类似,但不是这一行。
您可以通过明确指定INSERT的列来实现您要查找的内容。
如果您要在NewId
列上使用默认值,则需要在INSERT
语句中明确列出列名。默认情况下,SQL Server将按照它们在SELECT
中列出的顺序插入列,除非您提供足够的信息。明确列出列是一种最佳实践,无论是哪种方式,都是为了避免这种意外结果。
所以你的陈述最终会像这样:
INSERT INTO eventGroup_History
(
DoneBy,
Operation,
DoneAt,
<All the other columns that are masked by the *>
)
SELECT....