SCOPE_IDENTITY и вместо триггера вставки триггера - PullRequest
3 голосов
/ 16 сентября 2009

ОК, у меня есть таблица без естественного ключа, только столбец с целочисленной идентификацией в качестве первичного ключа. Я хотел бы вставить и получить значение идентификатора, но также использовать триггер, чтобы убедиться, что определенные поля всегда установлены. Первоначально дизайн должен был использовать вместо триггеров вставки, но это нарушает scope_identity. Предложение вывода в операторе вставки также нарушается триггером вместо вставки. Итак, я разработал альтернативный план и хотел бы знать, если что-то явно не так с тем, что я собираюсь сделать:

начать надуманный пример:

    CREATE TABLE [dbo].[TestData] (
    [TestId] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
    [Name] [nchar](10) NOT NULL)

    CREATE TABLE [dbo].[TestDataModInfo](
    [TestId] [int] PRIMARY KEY NOT NULL,
    [RowCreateDate] [datetime] NOT NULL)

    ALTER TABLE [dbo].[TestDataModInfo]  WITH CHECK ADD  CONSTRAINT
    [FK_TestDataModInfo_TestData] FOREIGN KEY([TestId])
    REFERENCES [dbo].[TestData] ([TestId]) ON DELETE CASCADE

CREATE TRIGGER [dbo].[TestData$AfterInsert]
   ON [dbo].[TestData]
   AFTER INSERT
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    INSERT INTO [dbo].[TestDataModInfo]
           ([TestId],
            [RowCreateDate])
        SELECT
            [TestId],
            current_timestamp
        FROM inserted

    -- Insert statements for trigger here

END

Конец надуманного примера.

Нет, я делаю это не для одного небольшого поля даты - это просто пример.

Поля, которые я хочу убедиться, установлены, были перемещены в отдельную таблицу (в TestDataModInfo), а триггер гарантирует, что она обновлена. Это работает, это позволяет мне использовать scope_identity () после вставок, и кажется безопасным (если мой триггер после сбоя, моя вставка завершится неудачно). Это плохой дизайн, и если да, то почему?

Ответы [ 4 ]

3 голосов
/ 16 сентября 2009

Как вы упоминали, SCOPE_IDENTITY предназначен для этой ситуации. На него не влияет триггерный код AFTER, в отличие от @@ IDENTITY.

Помимо использования сохраненных процедур, это нормально.

Я использую триггеры AFTER для аудита, потому что они удобны ... то есть записывают в другую таблицу в моем триггере.

Редактировать: SCOPE_IDENTITY и параллелизм в SQL Server 2005 cam имеют проблему

0 голосов
/ 30 июля 2012

Вы можете просто использовать триггер INSTEAD OF, в триггере захватывая значение сразу после вставки в основную таблицу, затем подменяя Scope_Identity() в @@Identity в конце триггера:

-- Inside of trigger
SET NOCOUNT ON;
INSERT dbo.YourTable VALUES(blah, blah, blah);
SET @YourTableID = Scope_Identity();

-- ... other DML that inserts to another identity-bearing table

-- Last statement in trigger
SELECT YourTableID INTO #Trash FROM dbo.YourTable WHERE YourTableID = @YourTableID;

Или, вот альтернативный заключительный оператор, который не использует чтения, но может вызвать проблемы с разрешениями, если исполняющий пользователь не имеет прав (хотя есть решения для этого).

SET @SQL =
   'SELECT identity(smallint, ' + Str(@YourTableID) + ', 1) YourTableID INTO #Trash';
EXEC (@SQL);

Обратите внимание, что Scope_Identity() может возвращать NULL для таблицы с триггером INSTEAD OF в некоторых случаях, даже если вы используете этот метод подмены. Но вы можете по крайней мере получить значение, используя @@Identity. Это может привести к тому, что проекты MS Access ADP снова начнут работать сразу после разрыва, потому что вы положили триггер на таблицу, в которую вставляет интерфейс.

Кроме того, помните, что любой параллелизм может заставить @@Identity и Scope_Identity() возвращать неверные значения - поэтому используйте OPTION (MAXDOP 1) или TOP 1 или однострочное предложение VALUES для решения этой проблемы.

0 голосов
/ 22 декабря 2011

Вы пробовали использовать:

SELECT scope_identity();

http://wiki.alphasoftware.com/Scope_Identity+in+SQL+Server+with+nested+and+INSTEAD+OF+triggers

0 голосов
/ 16 сентября 2009

Вы пытались использовать OUTPUT для возврата значения вместо этого?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...