简体   繁体   English

输出子句VS触发器

[英]output clause VS triggers

On our database, most tables have a dbupddate field which indicates the datetime of the last INSERT or UPDATE applied at the row. 在我们的数据库上,大多数表都有dbupddate字段,该字段指示在行上应用的最后一次INSERTUPDATEdatetime时间。

In order to avoid this field having an erroneous value, there exist triggers (sometimes AFTER , sometimes INSTEAD OF ) which make sure that in the end, the value is correct and not whatever "manual" other value someone might try to write into that field. 为了避免该字段具有错误的值,存在触发器(有时是AFTER ,有时是INSTEAD OF ),这些触发器确保最后该值是正确的,而不是其他人可能尝试写入该字段的“手动”其他值。

Now I am performing an update statement (actualy MERGE ) and I want to have an OUTPUT clause including that field. 现在,我正在执行一条更新语句(执行MERGE ),并且我想拥有一个包含该字段的OUTPUT子句。 As I've read in the appropriate MS article , OUTPUT ignores triggers. 正如我在相应的MS文章中所读到OUTPUT忽略触发器。

Is there any workaround to have OUTPUT return the value dbupddate has after the triggers? 有什么解决方法可以让OUTPUT在触发器之后返回dbupddate具有的值? I don't want to make another query to draw the info, because I am not guaranteed that in the split second between those queries, a third query of another user might not have changed quite everything. 我不想进行另一个查询来绘制信息,因为我不能保证在这些查询之间的瞬间,另一个用户的第三个查询可能并没有改变所有事情。


Results after following Larnu's suggestions 遵循Larnu的建议后的结果

I ran the examples provided, with the only exception of changing the default values of the updatetime fields to convert(datetime2,'1900-01-01') so that I might make some sense. 我运行了提供的示例,唯一的例外是将updatetime字段的default值更改为convert(datetime2,'1900-01-01')因此我可能会有所理解。 I ran each of the 4 queries, followed by a select from their respective table and compared the updatetime values: 我运行了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

I guess the output here ignores the trigger and returns the default value that was inserted before the after trigger took effect. 我猜这里的输出将忽略触发器,并返回在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

Same. 相同。 Now the crazy part comes. 现在疯狂的部分来了。 I drew both the inserted and the deleted dates out: 我把插入和删除的日期都画出来了:

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

So, in the update cases, the default value is not present, but I have different values in the actual table and in the query's output. 因此,在update情况下,默认值不存在,但实际表和查询输出中的值却不同。 I know neither how to make these values the same, nor what exactly happens with the datetimes in the update case. 我既不知道如何使这些值相同,也不知道更新案例中的日期时间到底发生了什么。

You can use OUTPUT with a TRIGGER but you also have to make use of the INTO clause as well. 您可以将OUTPUTTRIGGER一起使用,但也必须使用INTO子句。 Take these sample tables and triggers: 取得这些样本表和触发器:

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;

If we were to run the following SQL you would get an error: 如果我们运行以下SQL,您将得到一个错误:

INSERT INTO dbo.Sample1 (Someint)
OUTPUT inserted.*
SELECT 1;

Msg 334, Level 16, State 1, Line 44 The target table 'dbo.Sample1' of the DML statement cannot have any enabled triggers if the statement contains an OUTPUT clause without INTO clause. 消息334,级别16,状态1,第44行,如果该语句包含不带INTO子句的OUTPUT子句,则DML语句的目标表'dbo.Sample1'无法具有任何已启用的触发器。

The error gives you the tip here, use the INTO clause. 该错误为您提供了提示,请使用INTO子句。 Thus you can, instead, do: 因此,您可以执行以下操作:

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;

This works for both INSERT and UPDATE , regardless of if it's AFTER or INSTEAD OF : 这对INSERTUPDATE ,无论是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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM