Триггер SQL Server 2008 не работает правильно с несколькими вставками - PullRequest
0 голосов
/ 03 мая 2010

У меня есть следующий триггер;

CREATE TRIGGER trFLightAndDestination
ON checkin_flight
AFTER INSERT,UPDATE
AS
BEGIN
    IF NOT EXISTS
    (
                    SELECT 1 
            FROM Flight v
            INNER JOIN Inserted AS i ON i.flightnumber = v.flightnumber
            INNER JOIN checkin_destination AS ib ON ib.airport = v.airport
            INNER JOIN checkin_company AS im ON im.company = v.company
            WHERE i.desk = ib.desk AND i.desk = im.desk
    )
    BEGIN
        RAISERROR('This combination of of flight and check-in desk is not possible',16,1)
        ROLLBACK TRAN       
    END
END

Что я хочу, чтобы триггер делал, это проверял таблицы Flight, checkin_destination и checkin_company при добавлении новой записи для checkin_flight. Каждая запись checkin_flight содержит номер рейса и номер стола, где пассажиры должны зарегистрироваться для этого пункта назначения. Таблицы checkin_destination и checkin_company содержат информацию о компаниях и направлениях, ограниченных определенными стойками регистрации. При добавлении записи в checkin_flight мне нужна информация из таблицы полетов, чтобы получить пункт назначения и компанию с указанным номером рейса. Эту информацию необходимо сверять с имеющимися комбинациями регистрации для рейсов, направлений и компаний.

Я использую триггер, как указано выше, но когда я пытаюсь вставить неправильную комбинацию, триггер это позволяет. Что мне здесь не хватает?

РЕДАКТИРОВАТЬ 1: Я использую следующий оператор множественной вставки

INSERT INTO checkin_flight VALUES (5315,3),(5316,3),(5316,2)
//5315 is the flightnumber, 3 is the desknumber to checkin for that flight

РЕДАКТИРОВАТЬ 2: Протестировал вставку одной строки, которая невозможна, затем ошибка выдается правильно. Так что проблема заключается в многократной вставке.

Ответы [ 4 ]

1 голос
/ 03 мая 2010

Проблема в том, что условие будет истинным, если верна только одна из вставленных записей. Вы должны проверить правильность всех записей, например ::10000

if (
  (
    select count(*) from inserted
  ) = (
    select count(*) from flight v
    inner join inserted i ...
  )
) ...
1 голос
/ 03 мая 2010

Проблема в том, что ваша логика разрешает любую вставку, которая включает хотя бы один действительный набор значений. Сбой произойдет только в том случае, если все вставленных записей недействительны, вместо любых вставленных записей недействительными.

Измените свое "ЕСЛИ НЕ СУЩЕСТВУЕТ (...)" на утверждение "ЕСЛИ СУЩЕСТВУЕТ (...)" и измените свое утверждение SELECT для возврата недействительных рейсов.

например:

IF EXISTS
(
                SELECT 1 
        FROM Flight v
        INNER JOIN Inserted AS i ON i.flightnumber = v.flightnumber
        LEFT JOIN checkin_destination AS ib ON ib.airport = v.airport
             AND i.desk = ib.desk
        LEFT JOIN checkin_company AS im ON im.company = v.company
             AND i.desk = im.desk
        WHERE (im.desk IS NULL OR ib.desk IS NULL)
)
BEGIN
    RAISERROR('This combination of of flight and check-in desk is not possible',16,1)
    ROLLBACK TRAN       
END
1 голос
/ 03 мая 2010

Вставленная таблица может содержать несколько строк, и поэтому вся логика в триггере ДОЛЖНА быть в состоянии применить ко всем строкам. Идея триггеров должна срабатывать один раз за рядный эффект - распространенное недоразумение триггеров WRT. SQL Server будет стремиться объединить вызовы триггера для повышения производительности, когда они происходят в одной транзакции.

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

1 голос
/ 03 мая 2010

Я не уверен в вашей бизнес-логике, но вам нужно проверить, что запрос делает правильные вещи.

Ваша проблема - IF NOT EXISTS, если условие истинно для 1 из 3 строк в INSERTED, оно не существует. Вам нужно преобразовать его, чтобы найти строку с ошибками и использовать IF EXISTS, а затем ошибку.

Тем не менее, при срабатывании триггера наилучший выход из ошибки:

RAISERROR()
ROLLBACK TRANSACTION
RETURN

Я в некотором роде сомневаюсь, что отсутствие RETURN является вашей проблемой, но всегда лучше включать три R при сбое в триггере.

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