在我们的数据库中,大多数表都有一个dbupddate
字段,该字段指示该行上最后一个datetime
或INSERT
中应用的UPDATE
。
为了避免此字段的值有误,存在触发器(有时为AFTER
,有时为INSTEAD OF
),这些触发器可以确保最终值是正确的,而不是“手动”值有人可能会尝试在该字段中写入其他值。
现在,我正在执行一条更新语句(实际上是MERGE
),我想拥有一个包含该字段的OUTPUT
子句。如我在the appropriate MS article中所读,OUTPUT
忽略了触发器。
是否有变通办法让OUTPUT
在触发器之后返回值dbupddate
?我不想进行另一个查询来绘制信息,因为我不能保证在这些查询之间的瞬间,另一个用户的第三个查询可能并没有改变所有事情。
遵循Larnu的建议后的结果
我运行了提供的示例,唯一的例外是将default
字段的updatetime
值更改为convert(datetime2,'1900-01-01')
,以使我有些道理。我运行了这4个查询中的每一个,然后从它们各自的表中进行选择,并比较了updatetime
的值:
INSERT INTO dbo.Sample1 (Someint)
OUTPUT inserted.*
INTO @inserted
SELECT 1;
SELECT 'Sample1 INSERT',*
FROM @inserted; -- 1900-01-01 00:00:00.000000
select * from Sample1 -- 2018-11-05 13:12:13.141580
我想这里的输出将忽略触发器,并返回在after
触发器生效之前插入的默认值。
DECLARE @inserted table (ID int, Someint int, updatedtime datetime2(6))
INSERT INTO dbo.Sample2 (Someint)
OUTPUT inserted.*
INTO @inserted
SELECT 1;
SELECT 'Sample2 INSERT',* --1900-01-01 00:00:00.000000
FROM @inserted;
select * from Sample2 --2018-11-05 13:12:35.580190
相同。现在疯狂的部分来了。我把插入和删除的日期都画出来了:
DECLARE @updated table (ID int, Someint int, ins_updatedtime datetime2(6),del_updatedtime datetime2(6))
UPDATE dbo.Sample1
SET Someint = 2
OUTPUT Inserted.*,Deleted.updatetime
INTO @updated;
SELECT 'Sample1 UPDATE',*
FROM @updated; --Sample1 UPDATE 1 2 2018-11-05 13:30:01.348490 2018-11-05 13:30:01.348490
select * from Sample1 -- 1 2 2018-11-05 13:31:31.851047
DECLARE @updated table (ID int, Someint int, ins_updatedtime datetime2(6),del_updatedtime datetime2(6))
UPDATE dbo.Sample2
SET Someint = 2
OUTPUT Inserted.*,Deleted.updatetime
INTO @updated;
SELECT 'Sample2 UPDATE',* -- Sample2 UPDATE 1 2 2018-11-05 13:30:20.286422 2018-11-05 13:30:20.286422
FROM @updated;
select * from Sample2 --1 2 2018-11-05 13:31:51.679726
因此,在update
情况下,不存在默认值,但实际表和查询输出中的值却不同。我既不知道如何使这些值相同,也不知道在更新情况下日期时间到底发生了什么。
答案 0 :(得分:2)
您可以将OUTPUT
与TRIGGER
一起使用,但是还必须使用INTO
子句。获取这些示例表和触发器:
CREATE TABLE dbo.Sample1 (SomeID int IDENTITY(1,1),
Someint int,
updatetime datetime2(6) DEFAULT SYSDATETIME());
CREATE TABLE dbo.Sample2 (SomeID int IDENTITY(1,1),
Someint int,
updatetime datetime2(6) DEFAULT SYSDATETIME());
GO
CREATE TRIGGER dbo.AfterInsertUdpate ON dbo.Sample1
AFTER INSERT, UPDATE
AS
UPDATE S
SET S.updatetime = SYSDATETIME()
FROM dbo.Sample1 S
JOIN Inserted i ON S.SomeID = i.SomeID;
GO
CREATE TRIGGER dbo.InsteadInsert ON dbo.Sample2
INSTEAD OF INSERT
AS
INSERT INTO dbo.Sample2 (Someint,
updatetime)
SELECT Someint, SYSDATETIME()
FROM Inserted;
GO
CREATE TRIGGER dbo.InsteadUpdate ON dbo.Sample2
INSTEAD OF UPDATE
AS
UPDATE S
SET S.Someint = i.Someint,
S.updatetime = SYSDATETIME()
FROM dbo.Sample2 S
JOIN Inserted i ON S.SomeID = i.SomeID;
如果我们运行以下SQL,则会收到错误消息:
INSERT INTO dbo.Sample1 (Someint)
OUTPUT inserted.*
SELECT 1;
334级第1州第44行的消息334 如果该语句包含不带INTO子句的OUTPUT子句,则DML语句的目标表'dbo.Sample1'不能具有任何已启用的触发器。
该错误为您提供了提示,请使用INTO
子句。因此,您可以执行以下操作:
DECLARE @inserted table (ID int, Someint int, updatedtime datetime2(6))
INSERT INTO dbo.Sample1 (Someint)
OUTPUT inserted.*
INTO @inserted
SELECT 1;
SELECT 'Sample1 INSERT',*
FROM @inserted;
这对INSERT
和UPDATE
均适用,无论是AFTER
还是INSTEAD OF
:
DECLARE @inserted table (ID int, Someint int, updatedtime datetime2(6))
INSERT INTO dbo.Sample2 (Someint)
OUTPUT inserted.*
INTO @inserted
SELECT 1;
SELECT 'Sample2 INSERT',*
FROM @inserted;
GO
DECLARE @updated table (ID int, Someint int, updatedtime datetime2(6))
UPDATE dbo.Sample1
SET Someint = 2
OUTPUT Inserted.*
INTO @updated;
SELECT 'Sample1 UPDATE',*
FROM @updated;
GO
DECLARE @updated table (ID int, Someint int, updatedtime datetime2(6))
UPDATE dbo.Sample2
SET Someint = 2
OUTPUT Inserted.*
INTO @updated;
SELECT 'Sample2 UPDATE',*
FROM @updated;
GO
--Clean up
DROP TABLE dbo.Sample1;
DROP TABLE dbo.Sample2;