Geo*_*tis 5 sql t-sql sql-server output-clause database-trigger
在我们的数据库中,大多数表都有一个dbupddate字段指示datetime最后一个INSERT或UPDATE应用于该行。
为了避免该字段具有错误的值,存在触发器(有时AFTER,有时INSTEAD OF)来确保最终该值是正确的,而不是有人尝试写入该字段的任何“手动”其他值。
现在我正在执行更新语句(实际上MERGE),并且我想要一个OUTPUT包含该字段的子句。正如我在相应的 MS 文章中读到的,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
Run Code Online (Sandbox Code Playgroud)
我猜这里的输出会忽略触发器并返回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
Run Code Online (Sandbox Code Playgroud)
相同的。现在疯狂的部分来了。我画出了插入日期和删除日期:
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
Run Code Online (Sandbox Code Playgroud)
因此,在这种update情况下,默认值不存在,但我在实际表和查询的输出中具有不同的值。我既不知道如何使这些值相同,也不知道更新情况下的日期时间到底发生了什么。
您可以OUTPUT与 a 一起使用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;
Run Code Online (Sandbox Code Playgroud)
如果我们运行下面的 SQL,你会得到一个错误:
INSERT INTO dbo.Sample1 (Someint)
OUTPUT inserted.*
SELECT 1;
Run Code Online (Sandbox Code Playgroud)
消息 334,级别 16,状态 1,第 44 行 如果 DML 语句的目标表“dbo.Sample1”包含不带 INTO 子句的 OUTPUT 子句,则该语句不能具有任何启用的触发器。
该错误给了你提示,请使用该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;
Run Code Online (Sandbox Code Playgroud)
这适用于 和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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3225 次 |
| 最近记录: |