Получить ROWCOUNT из вместо триггера
устаревшее приложение выполняет вставку в таблицу с триггером вместо триггера и впоследствии использует rowcount для дальнейшей обработки.
Теперь нам нужно отказаться от некоторых вставок с использованием INSTEAD OF INSERT
триггер.
проблема в том, что @@ROWCOUNT по-прежнему возвращает число попытка вставками.
например, фиктивный триггер, который никогда не завершит вставку, может быть
ALTER TRIGGER [dbo].[trig_ACCOUNT_CREDITS_RunningTotalINSERT]
ON [dbo].[ACCOUNT_CREDITS]
INSTEAD OF INSERT
AS
BEGIN
--tried with NOCOUNT ON and OFF
SET NOCOUNT OFF;
--This is an example of the branching logic that might determine
--whether or not to do the INSERT
IF 1=2 --no insert will ever occur (example only)
BEGIN
INSERT INTO dbo.ACCOUNT_CREDITS (COL1, COL2)
SELECT COL1, COL2 from INSERTED
END
END
и некоторые инструкции INSERT может быть
--No rows will be inserted because value of COL1 < 5
INSERT INTO dbo.ACCOUNT_CREDITS (COL1, COL2) VALUES ( 3, 3)
--We would assume row count to be 0, but returns 1
select @@ROWCOUNT
--No rows will be inserted because value of COL1 < 5
INSERT INTO dbo.ACCOUNT_CREDITS (COL1, COL2)
SELECT 1, 1
union all
SELECT 2, 2
--We would assume row count to be 0, but returns 2
select @@ROWCOUNT
Я могу обойти проблему, но меня беспокоит, что я не могу доверять @@ROWCOUNT. Я не могу найти ссылки на эту проблему на SO или those другое банки знаний. Это просто случай ТРИГГЕРЫ-ЭТО ЗЛО?
могу ли я повлиять на @@ROWCOUNT?
2 ответов
некоторые операторы могут изменить @@ROWCOUNT внутри триггера.
сообщении
SELECT * FROM INSERTED WHERE COL1 < 5
выполняет и устанавливает @@ROWCOUNT в 1
положите заявления
SET NOCOUNT ON;
затем
IF NOT EXISTS (SELECT * FROM INSERTED WHERE COL1 < 5)
BEGIN
SET NOCOUNT OFF;
INSERT INTO dbo.ACCOUNT_CREDITS (COL1, COL2)
SELECT COL1, COL2 from INSERTED
END
Проблема
мне нужна информация в контексте основного процесса, которая доступна только в контексте триггера.
Решение
получают ли @@ROWCOUNT
или что-нибудь другое С триггер, или даже передача информации to триггер, существует два метода, которые позволяют обмениваться информацией с триггерами:
локальные временные таблицы (т. е. таблицы с именами, начинающимися с одного
#
:#tmp
)
я опубликовал пример использования CONTEXT_INFO
в ответе на соответствующий вопрос в DBA.Клиент StackExchange: передача информации о том, кто удалил запись на триггер удаления. В комментариях к этому ответу было обсуждение, связанное с возможными осложнениями вокруг CONTEXT_INFO
, вот я и выложил еще один ответ по этому вопросу, используя вместо этого временную таблицу.
так как этот пример касался отправки информации to триггер, ниже приведен пример получения информации С триггер, поскольку это то, о чем этот вопрос:
первый: создать простую таблицу
CREATE TABLE dbo.InsteadOfTriggerTest (Col1 INT);
второй: создать триггер
CREATE TRIGGER dbo.tr_InsteadOfTriggerTest
ON dbo.InsteadOfTriggerTest
INSTEAD OF INSERT
AS
BEGIN
PRINT 'Trigger (starting): ' + CONVERT(NVARCHAR(50), @@ROWCOUNT);
SET NOCOUNT ON; -- do AFTER the PRINT else @@ROWCOUNT will be 0
DECLARE @Rows INT;
INSERT INTO dbo.InsteadOfTriggerTest (Col1)
SELECT TOP (5) ins.Col1
FROM inserted ins;
SET @Rows = @@ROWCOUNT;
PRINT 'Trigger (after INSERT): ' + CONVERT(NVARCHAR(50), @Rows);
-- make sure temp table exists; no error if table is missing
IF (OBJECT_ID('tempdb..#TriggerRows') IS NOT NULL)
BEGIN
INSERT INTO #TriggerRows (RowsAffected)
VALUES (@Rows);
END;
END;
третий: Do тест
SET NOCOUNT ON;
IF (OBJECT_ID('tempdb..#TriggerRows') IS NOT NULL)
BEGIN
DROP TABLE #TriggerRows;
END;
CREATE TABLE #TriggerRows (RowsAffected INT);
INSERT INTO dbo.InsteadOfTriggerTest (Col1)
SELECT so.[object_id]
FROM [master].[sys].[objects] so;
PRINT 'Final @@ROWCOUNT (what we do NOT want): ' + CONVERT(NVARCHAR(50), @@ROWCOUNT);
SELECT * FROM #TriggerRows;
вывод (на вкладке Сообщения):
триггер (запуск): 91
Триггер (после вставки): 5
Final @@ROWCOUNT (чего мы не хотим): 91
результаты:
RowsAffected
5