Запретить вставку перекрывающихся диапазонов дат с помощью триггера SQL - PullRequest
7 голосов
/ 26 октября 2010

У меня есть таблица, которая упрощенно выглядит следующим образом:

create table Test
(
 ValidFrom date not null,
 ValidTo date not null,
 check (ValidTo > ValidFrom)
)

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

create trigger Trigger_Test
on Test
for insert
as
begin
 if exists(
  select *
  from Test t
   join inserted i
   on ((i.ValidTo >= t.ValidFrom) and (i.ValidFrom <= t.ValidTo))
 )
 begin
  raiserror (N'Overlapping range.', 16, 1);
  rollback transaction;
  return
 end;
end

Но это не работает, так как моя недавно вставленная запись является частью обеих таблиц Проверка и вставка внутри триггера. Таким образом, новая запись во вставленной таблице всегда присоединяется к себе в тестовой таблице. Триггер всегда отменяет переход.

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

Основной вопрос

Можно ли написать триггер, который будет работать должным образом, без добавления дополнительного столбца идентификаторов в мою таблицу тестов, который я мог бы использовать для исключения вновь вставленных записей из моего оператора exists(), например:

create trigger Trigger_Test
on Test
for insert
as
begin
 if exists(
  select *
  from Test t
   join inserted i
   on (
    i.ID <> t.ID and /* exclude myself out */
    i.ValidTo >= t.ValidFrom and i.ValidFrom <=t.ValidTo
   )
 )
 begin
  raiserror (N'Overlapping range.', 16, 1);
  rollback transaction;
  return
 end;
end

Важно : Если невозможно без идентичности - единственный ответ, я приветствую вас, чтобы представить его вместе с разумным объяснением, почему.

Ответы [ 2 ]

5 голосов
/ 17 июня 2011

Я знаю, что на этот вопрос уже дан ответ, но я недавно решил эту проблему и придумал что-то, что работает (и работает хорошо, выполняя поиск по одному для каждой вставленной строки).Смотрите пример в этой статье: http://michaeljswart.com/2011/06/enforcing-business-rules-vs-avoiding-triggers-which-is-better/

(и он не использует столбец идентификаторов)

3 голосов
/ 26 октября 2010

Два небольших изменения, и все должно работать нормально.

Сначала добавьте предложение where в триггер, чтобы исключить повторяющиеся записи из объединения. Тогда вы не будете сравнивать вставленные записи с самими собой:

select *
  from testdatetrigger t
   join inserted i
   on ((i.ValidTo >= t.ValidFrom) and (i.ValidFrom <= t.ValidTo))
  Where not (i.ValidTo=t.Validto and i.ValidFrom=t.ValidFrom)

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

...