2016-02-11 5 views
0

У меня проблема с триггером SQL. Это триггер «ПОСЛЕ ВСТАВКИ». Он работает для каждого блока IF EXISTS, за исключением одного с обновлением и повышением ошибок, как показано ниже. Он либо обновляется, либо перемещается, либо останавливается и не обновляется.SQL Trigger - After Insert - Оператор обновления и RAISERROR не работают

Код: (где я остановился - несколько разных попыток у него и все они потерпели неудачу)

IF EXISTS (SELECT 
        [RPS].[Slip] 
       FROM 
        [DC].[dbo].[Slips] AS [RPS] 
       WHERE 
        [RPS].[Slip] = @ps 
        AND [RPS].[Status] = 0) 
       BEGIN  
        BEGIN TRAN; 
          UPDATE 
           [DC].[dbo].[Slips] 
          SET 
           [Slip].[Status] = 1 
          FROM 
           [DC].[dbo].[Slips] 
          WHERE 
           [Slips].[Slip] = @ps; 

         SET @msg = ' ' + @NewLine + 'Inv. Decremented - Rollback' + @NewLine + 'Contact HD.' + @NewLine; 

         RAISERROR (@msg,16,1); 
         COMMIT TRAN; 
         RETURN; 
       END; 

Цель состоит в том, чтобы обновить таблицу в состояние 1, когда IF СУЩЕСТВУЕТ пойман и уволить RAISERROR. RAISERROR подхватывается кодом java и останавливает обработку. Если я выберу обновление, триггер вызывает ошибку и останавливается. Если я возьму ошибку рейза, триггер обновится, но движется дальше - и я не хочу этого ... Я хочу мой торт и съеду его тоже!

Мысли?

+0

Триггеры запускают неявную транзакцию, поэтому ваша явная транзакция в триггере фактически является вложенной. SQL Server не соблюдает вложенные транзакции, и, вероятно, там что-то происходит. Я бы просто удалил вашу явную транзакцию и посмотрел, работает ли это для вас. –

+2

Исправление к вышеуказанному комментарию. Дело не в том, что SQL Server «не соблюдает вложенные транзакции», но семантика может немного отличаться от того, что вы ожидаете. SQL Server отслеживает уровень вложенности в '@@ trancount', и только внешний' commit' (тот, который заставляет '@@ trancount' переходить от 1 до 0), фактически совершит транзакцию. Откат (без точки сохранения), однако, откат транзакции, принимающей '@@ trancount', равен 0. –

+2

« BEGIN TRAN »является излишним. Он может быть безопасно удален без влияния на поведение триггера, который, как указывает @JohnSpecko, уже имеет неявную транзакцию. Я не ожидаю, что это исправит любую проблему, с которой вы столкнулись. Имеет ли [DC]. [Dbo]. [Slips] есть триггер обновления, и у этого триггера обновления есть оператор ROLLBACK в нем случайно? Что может случиться, так это то, что 'ROLLBACK' откатывает все, включая все вложенные транзакции, включая вашу работу. –

ответ

2

Чтобы предотвратить обновление исходной таблицы при запуске, позволяя обновлению таблицы Slips, вам понадобится триггер INSTEAD OF INSERT, VIEW и цепочка прав собственности, чтобы предотвратить прямое изменение базовой таблицы пользователями или их применением. код. Вы не можете попасть туда с использованием традиционного триггера AFTER UPDATE по причинам, упомянутым ранее в комментариях, а именно потому, что как триггерная вставка, так и инициированное обновление обернуты в одну транзакцию, они должны либо вступить в силу, либо не вступить в силу. Вы не можете совершать только часть транзакции, и вложенная транзакция является частью самой внешней транзакции, в которой она содержится.

Теперь для решения ...

Части 1 - The View Создать представление с той же структурой столбца и обозначением в качестве таблицы, которая имеет вставки триггера, который дает вам все эти проблемы. Что-то вида:

CREATE VIEW [same-name-as-the-table-you-are-using] 
AS 
    SELECT <list-all-columns-explicitly-please-dont-use-star> 
    FROM <original-table-with-slightly-different-name-now> 

Если исходная таблица с именем XXX затем переименовать его что-то вроде XXX_SINK и использовать XXX для просмотра. Разработчики пользователей и приложений должны рассмотреть это представление как «таблицу», которую они используют.

Часть 2 - цепочки владения собственности в цепи устанавливаются в SQL Server, когда объект реферирования и объект ссылки имеют один и тот же владелец. Когда другая сторона (а не владелец) обращается к ссылочному объекту (в этом случае к представлению), разрешения для этой стороны оцениваются по отношению к объекту ссылки, как обычно, но не не оценивается в отношении объекта, на который делается ссылка (в этом случае Таблица). Это была особенность SQL Server с самого начала, но не известна или не понятна ряду разработчиков SQL. Вы можете получить более подробную информацию о ownership chains here.

Вы захотите отклонить права доступа к базе пользователей к таблице и предоставить их представлению. Это означает, что пользователи могут вставлять или обновлять строки только через представление, а не непосредственно в таблицу. Это важно, потому что вы не хотите, чтобы они в обход, что вы будете делать в следующей части ...

Часть 3 - ВМЕСТО Trigger Создание INSTEAD OF триггера на представлении.Синтаксис подобен синтаксису триггера AFTER, за исключением слов INSTEAD OF вместо AFTER и что никакой операции вставки не произошло еще в момент его запуска, и если сам триггер не активирует обновление в таблице «сток», обновление не будет будет выполняться вообще. Этот триггер может смешивать и сопоставлять все, что пожелает. Подобно триггеру AFTER, подразумевается транзакция, но выполняются только явные операции модификации данных в самом триггере.

Помните, что триггер должен явно выполнить insert в нижнюю таблицу раковины. Строки, которые нужно вставить, можно извлечь из специальной таблицы inserted, как в случае триггера AFTER. Помните, что (по крайней мере, для SQL Server) может быть добавлено более одной строки (на самом деле в случае оператора insert с нулевой строкой могут быть нулевые строки). Вам нужно будет решить, разрешать ли хорошие строки или запрещать вставку всех строк. Учитывая ваши требования, я подозреваю, что позже.

Собственно дизайн звука базы данных, я бы настоятельно рекомендовал против -

  1. Спускового ограничение вставки в отдельные строки и
  2. Использованием любой формы курсора внутри триггера, чтобы иметь дело с многорядным вставки. Вместо этого используйте set-oriented DML.

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

Разумный RAISERROR (то есть с разумными значениями серьезности и состояния) не приведет к тому, что что-либо будет отменено или откат.

Выполнение этих действий в этой комбинации должно привести к желаемому результату.