Выходное предложение VS триггеров
В нашей базе данных большинство таблиц имеют dbupddate
поле, которое указывает на datetime
из последних INSERT
или же UPDATE
применяется в ряду.
Чтобы это поле не имело ошибочного значения, существуют триггеры (иногда AFTER
иногда INSTEAD OF
), которые в конечном итоге обеспечивают правильность значения, а не "ручного" другого значения, которое кто-либо может попытаться записать в это поле.
Сейчас я выполняю заявление об обновлении (на самом деле MERGE
) и я хочу иметь OUTPUT
пункт, включающий это поле. Как я прочитал в соответствующей статье MS, OUTPUT
игнорирует триггеры.
Есть ли обходной путь, чтобы иметь OUTPUT
вернуть значение dbupddate
после триггеров? Я не хочу делать еще один запрос для извлечения информации, потому что я не гарантирую, что за долю секунды между этими запросами третий запрос другого пользователя мог не изменить совсем ничего.
Результаты после следования советам Ларну
Я запустил предоставленные примеры, за единственным исключением изменения 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
В некоторых случаях значение по умолчанию отсутствует, но у меня есть разные значения в фактической таблице и в выводе запроса. Я не знаю ни как сделать эти значения одинаковыми, ни что именно происходит с datetime в случае обновления.
1 ответ
Ты можешь использовать 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, Уровень 16, Состояние 1, Строка 44 В целевой таблице 'dbo.Sample1' оператора DML не может быть никаких включенных триггеров, если оператор содержит предложение OUTPUT без предложения INTO.
Ошибка дает вам подсказку здесь, используйте 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;