У меня были серьезные сомнения относительно использования @@ identity, потому что это может вернуть неправильный ответ.
Но есть обходной путь, заставляющий @@ identity иметь значение scope_identity ().
Просто для полноты, сначала я перечислю несколько других способов решения этой проблемы, которые я видел в Интернете:
Заставить триггер возвращать набор строк. Затем в пакете SP, который выполняет вставку, выполните INSERT Table1 EXEC sp_ExecuteSQL ...
для еще одной таблицы. Тогда scope_identity () будет работать. Это грязно, потому что требует динамического SQL, что является болью. Также следует помнить, что динамический SQL запускается с разрешениями пользователя, вызывающего SP, а не с разрешениями владельца SP. Если исходный клиент мог вставить в таблицу, он все равно должен иметь это разрешение, просто знайте, что у вас могут возникнуть проблемы, если вы откажете в разрешении на вставку непосредственно в таблицу.
Если есть другой кандидатный ключ, получите идентификатор вставленной строки (строк), используя эти ключи. Например, если имя имеет уникальный индекс, вы можете вставить, а затем выбрать (максимум для нескольких строк) идентификатор из таблицы, которую вы только что добавили, используя имя. Хотя это может иметь проблемы с параллелизмом, если другой сеанс удаляет только что вставленную строку, это не хуже, чем в исходной ситуации, если кто-то удалил вашу строку до того, как приложение сможет ее использовать.
Теперь вот как окончательно сделать ваш триггер безопасным для @@ Identity, чтобы он возвращал правильное значение, , даже если ваш SP или другой триггер вставляется в таблицу, содержащую тождество, после основной вставки .
Кроме того, пожалуйста, добавьте в свой код комментарии о том, что вы делаете и почему, чтобы будущие посетители триггера не ломали вещи и не тратили время на попытки выяснить это.
CREATE TRIGGER TR_MyTable_I ON MyTable INSTEAD OF INSERT
AS
SET NOCOUNT ON
DECLARE @MyTableID int
INSERT MyTable (Name, SystemUser)
SELECT I.Name, System_User
FROM Inserted
SET @MyTableID = Scope_Identity()
INSERT AuditTable (SystemUser, Notes)
SELECT SystemUser, 'Added Name ' + I.Name
FROM Inserted
-- The following statement MUST be last in this trigger. It resets @@Identity
-- to be the same as the earlier Scope_Identity() value.
SELECT MyTableID INTO #Trash FROM MyTable WHERE MyTableID = @MyTableID
Обычно дополнительная вставка в таблицу аудита будет нарушать все, потому что, поскольку у нее есть столбец идентификаторов, @@ Identity вернет это значение вместо того, которое вставлено в MyTable. Однако при окончательном выборе создается новое правильное значение @@ Identity, основанное на Scope_Identity (), из которого мы сохранили ранее. Это также защищает от любого возможного дополнительного триггера ПОСЛЕ таблицы MyTable.
Обновление:
Я только что заметил, что триггер INSTEAD OF здесь не нужен. Это делает все, что вы искали:
CREATE TRIGGER dbo.TR_Payments_Insert ON dbo.Payment FOR INSERT
AS
SET NOCOUNT ON;
IF EXISTS (
SELECT *
FROM
Inserted I
INNER JOIN dbo.Payment P ON I.CustomerID = P.CustomerID
WHERE
I.DateFrom < P.DateTo
AND P.DateFrom < I.DateTo
) ROLLBACK TRAN;
Это, конечно, позволяет scope_identity () продолжать работать. Единственным недостатком является то, что откатная вставка в таблице идентификаторов действительно использует использованные значения идентификаторов (значение идентификатора все еще увеличивается на число строк в попытке вставки).
Я смотрел на это несколько минут и сейчас не уверен в этом, но я думаю, это сохраняет значение инклюзивного времени начала и эксклюзивного времени окончания. Если бы время окончания было включительно (что было бы странно для меня), тогда для сравнения нужно было бы использовать <= вместо <. </p>