2 Вопрос: Триггер, чтобы избежать двойных бронирований

вопрос создан в Wed, May 8, 2019 12:00 AM

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

CREATE TRIGGER dbo.doubleBookRevised
ON dbo.tblBookingDetailsRevised
AFTER INSERT
AS
IF Exists (SELECT * FROM inserted i JOIN
dbo.tblBookingDetailsRevised bdr
ON i.locationID = bdr.locationID AND
i.bookedFor = bdr.bookedFor AND
i.bookedTimeSlot = bdr.bookedTimeSlot)
BEGIN RAISERROR ('Double bookings are not allowed.', 16, 1)
ROLLBACK TRANSACTION
RETURN
END
GO

Я уже реализовал некоторую логику во внешнем интерфейсе C # для предотвращения двойного бронирования, но когда я запустил программу, она успешно прошла проверку внешнего интерфейса, но пометил ложное срабатывание при попытке записи в таблицу.

Я использовал это для справки, но не могу понять, что отличается в моей реализации от решения здесь. Предотвращение двойного бронирования в SQL

РЕДАКТИРОВАТЬ: Следуя совету, я изменил триггер из ПОСЛЕ ВСТАВКИ в INSTEAD OF INSERT для следующего;

INSTEAD OF INSERT
AS
IF (NOT Exists (SELECT * FROM inserted i JOIN
dbo.tblBookingDetailsRevised bdr
ON (i.locationID = bdr.locationID) AND
(i.bookedFor = bdr.bookedFor) AND
(i.bookedTimeSlot = bdr.bookedTimeSlot)))
INSERT INTO tblBookingDetailsRevised (bookingID, bookedFor, locationID, bookedTimeSlot, detailEquip) 
SELECT i.bookingID, i.bookedFor, i.locationID, i.bookedTimeSlot, i.detailEquip 
FROM inserted i
ELSE
BEGIN RAISERROR ('Double bookings are not allowed.', 16, 1)
RETURN
END
    
0
  1. Вы пытались использовать ограничение UNIQUE?
    2019-05-08 16: 00: 21Z
  2. Ваш триггер - AFTER INSERT, поэтому вы проверяете таблицу на предмет бронирования, который вы только что вставили. Если вы положите синий шар в сумку, а затем проверьте, есть ли синий шар в сумке, он всегда будет там. Это похоже на работу для уникального индекса /ограничения.
    2019-05-08 16: 00: 51Z
  3. Будьте осторожны здесь. Откат транзакции в триггере может быть проблематичным. Если у вас есть другая транзакция вне оператора вставки, у вас будут проблемы.
    2019-05-08 16: 01: 56Z
  4. @ LuisCazares проблема в том, что просматриваемые уникальные идентификаторы уникальны только при совместном просмотре; иначе я мог бы положиться на первичные ключи, чтобы предотвратить это. Чтобы дать немного контекста, значение bookedFor является датой, но оно в сочетании с уникальным ключом делает первичный ключ другой таблицы, унаследованной здесь как часть составного ключа, и вы можете иметь несколько одинаковых дат и разных местоположение или время и т. д. Вместо этого я постараюсь реализовать триггер INSTEAD OF INSERT
    2019-05-08 16: 13: 23Z
2 ответа                              2                         

Проблема в том виде, в каком она была опубликована, может быть решена с помощью простого УНИКАЛЬНОГО ОГРАНИЧЕНИЯ, включающего 3 столбца. Нет причин изобретать велосипед.

ALTER TABLE dbo.tblBookingDetailsRevised 
ADD CONSTRAINT UQ_BookingDetailsRevised UNIQUE (locationID, bookedFor, bookedTimeSlot); 

Если не происходит что-то еще и информация отсутствует в вопросе.

    
1
2019-05-08 16: 57: 24Z
  1. Это похоже на правильное решение. , , полностью избегать триггера.
    2019-05-08 18: 37: 58Z
  2. Ага, да, решение кажется намного проще и чище
    2019-05-10 08: 52: 07Z

Вы используете триггер AFTER INSERT, что означает, что строка вставлена ​​до проверки IF EXISTS в триггерах. Поскольку он находится в той же транзакции, что и вставка, то вы будете сопоставлять недавно добавленную строку и получите положительный результат. Если вы хотите перехватить его перед вставкой, используйте триггер INSTEAD OF INSERT и обработайте вставку внутри триггера.

    
0
2019-05-08 16: 07: 09Z
  1. У меня естьМы попытались реализовать оператор INSTEAD OF INSERT, как вы и предлагали, однако я заметил, что когда я делаю это, на вкладке «Результаты» диспетчера SQL Server дважды отображается «1 строка затронута». Мне было любопытно, если я сделал ошибку в реализации; Я отредактировал новый триггер в исходное сообщение
    2019-05-08 16: 32: 27Z
  2. Это нормально. Сервер SQL сообщает о начальной вставке и вставке триггера как отдельные команды, даже если INSTEAD OF INSERT заменяет INSERT.
    2019-05-08 16: 34: 34Z
источник размещен Вот