Как я могу предотвратить совпадение дат в SQL? - PullRequest
5 голосов
/ 06 марта 2012

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

hireId int primary key
carId int not null foreign key
onHireDate datetime not null
offHireDate datetime not null

Я пытаюсь запрограммировать многопользовательскую систему, которая не допускает перекрытия периодов onhire и offhire для автомобилей. Мне нужно иметь возможность добавлять сотрудников в непоследовательном порядке. Также необходимо разрешить редактирование найма.

Любой способ ограничить таблицы или использовать триггеры и т. Д. Для предотвращения наложений? Я использую Entity Framework, поэтому я хотел бы вставить в таблицу в обычном режиме, а затем, если он не удается, вывести какое-то ловимое исключение и т. Д.

Ответы [ 3 ]

3 голосов
/ 06 марта 2012

Рассмотрим этот запрос:

SELECT *
FROM Hire AS H1, Hire AS H2
WHERE H1.carId = H2.carId
AND H1.hireId < H2.hireId 
AND 
   CASE 
   WHEN H1.onHireDate > H2.onHireDate THEN H1.onHireDate 
   ELSE H2.onHireDate END
   <
   CASE 
   WHEN H1.offHireDate > H2.offHireDate THEN H2.offHireDate 
   ELSE H1.offHireDate END

Если все строки соответствуют вашему бизнес-правилу, тогда этот запрос будет пустым набором (при условии закрытое-открытое представление периодов , то есть где дата окончанияявляется самой ранней временной гранулой, которая не рассматривается в течение периода).

Поскольку SQL Server не поддерживает подзапросы в пределах CHECK ограничений , поместите ту же логику в триггер (но не вТриггер INSTEAD OF, если вы не можете предоставить логику для разрешения перекрытий).


Альтернативный запрос с использованием Фаулера :

SELECT *
  FROM Hire AS H1, Hire AS H2
 WHERE H1.carId = H2.carId
       AND H1.hireId < H2.hireId 
       AND H1.onHireDate < H2.offHireDate 
       AND H2.onHireDate < H1.offHireDate;
3 голосов
/ 06 марта 2012
CREATE TRIGGER tri_check_date_overlap ON your_table
INSTEAD OF INSERT 
AS
BEGIN
    IF @@ROWCOUNT = 0
       RETURN

    -- check for overlaps in table 'INSERTED'
    IF EXISTS(
        SELECT hireId FROM your_table WHERE 
             (INSERTED.onHireDate BETWEEN onHireDate AND offHireDate) OR
             (INSERTED.offHireDate BETWEEN onHireDate AND offHireDate) 
    )
        BEGIN   
           -- exception? or do nothing?
        END
    ELSE
        BEGIN
        END
END
GO
0 голосов
/ 22 января 2013

Я сейчас использую методы проектирования, управляемые доменом.Это мешает мне беспокоиться о триггерах базы данных и т. Д. И сохраняет всю логику в .Net-коде.Ответ здесь, чтобы люди могли видеть альтернативу.

Я рассматриваю родителя коллекции периодов как совокупный корень , а корень имеет временную метку.Совокупный корень - это границы согласованности для транзакций, распределений и параллелизма (см. Эванс - то, что я узнал со времен синей книги ).Это используется для проверки того, когда в базе данных в последний раз было подтверждено любое изменение.

У меня есть способы добавить периоды найма в родительский объект.Я проверяю перекрытие при добавлении движения в совокупный корень.Например, AddHire(start,end) - подтвердит, что это не создает перекрытия для объекта в домене памяти.

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

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

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