Ограничение SQL для нескольких значений - PullRequest
1 голос
/ 17 августа 2010

Вот мой стол

Events
Start : Datetime
End : Datetime

Я пытаюсь убедиться, что новое событие не перекрывает ранее введенные события. Я признаю, что мои знания SQL в лучшем случае новичок. Ниже приводится оператор выбора, который приближает меня, но я не могу понять, как превратить его в ограничение (я бы использовал проверку?)

SELECT e.*
FROM Events
WHERE Start BETWEEN e.START and e.END
OR End BETWEEN new.START and new.END
OR (Start < e.Start and End > e.End)

Я бы вообразил, если что-то подобное вернуло что-то вообще, есть совпадение.

Редактировать: обновлен оператор "sql" для покрытия логического сбоя с моей стороны. Скорее всего, он все еще плохо сформирован. Я действительно ценю всю помощь!

Ответы [ 4 ]

4 голосов
/ 17 августа 2010

Это на самом деле должно идти в код или триггер. Ограничение действует только на уровне строк

CREATE TRIGGER TRG_Events_INSERT On EventsFOR INSERT
AS
IF EXISTS (SELECT *
    FROM Events E
        JOIN
        INSERTED INS
         ON
           (E.Start Between INS.START and INS.END)
          OR
           (E.End Between INS.START and INS.END)
          OR
           (E.Start < INS.START and E.End > INS.END)

     WHERE
        E.Key <> INS.Key --already inserted at this point

BEGIN
   ROLLBACK TRAN
   --etc
END
GO
3 голосов
/ 17 августа 2010

Указанный вами SQL не является синтаксически правильным - используйте:

SELECT e.*
  FROM EVENTS e
 WHERE start BETWEEN e.START and e.END
    OR end BETWEEN e.START and e.END
    OR (start < e.START AND end > e.END)

BETWEEN включительно и поддерживается последовательно во всех базах данных.

1 голос
/ 17 августа 2010

Это, вероятно, будет зависеть от используемой СУБД, но такое ограничение обычно необходимо реализовать с использованием триггера , который выполняет запрос, чтобы определить, является ли вставка / обновление действительным, и выполняет откат вернуть транзакцию, если нет. Ограничения CHECK обычно позволяют ссылаться только на столбцы в «текущей строке».

SELECT *
FROM Events E
WHERE E.Start <= NEWEND
AND E.End >= NEWSTART

... выдаст вам события, которые перекрываются (замените <= и> = на <и>, если вас не интересуют «трогательные» события).

0 голосов
/ 17 августа 2010

Что вы можете сделать, это сравнить таблицу с самим собой в объединении.Ниже приведен пример того, как это сделать.Я закомментировал несколько строк.Раскомментируйте их, чтобы увидеть прогресс в работе с различными делами.

edit: Если вам нужно это как ограничение для самой таблицы, вы должны использовать триггер.

edit2: Для SQL 2005 замените синтаксис вставки отдельными операторами вставки.

Удачи,

GJ

declare @event table (
    Id int,
    Start DateTime,
    Stop DateTime
)

insert  @event (Id, Start, Stop)
values  (1, '2010-08-01', '2010-08-02')
    ,(2, '2010-08-04', '2010-08-06')
    ,(3, '2010-08-05', '2010-08-08')    -- start fals within event 2
    --,(4, '2010-01-01', '2010-12-31')  -- overlaps with all of them
    --,(5, '2010-08-01', '2010-08-02')      -- equal to event 1

select  *
from    @event e1
        inner join @event e2 
            on  e1.Id != e2.Id          -- do not compare to itself
            and e2.Start >= e1.Start    -- events that have a start date
            and e2.Start <= e1.Stop
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...