Ограничение с функцией, которая содержит Select, никогда не выполняется - PullRequest
2 голосов
/ 17 февраля 2020

У меня есть такая таблица:

CREATE TABLE CarRentSchedule
(
    carId INTEGER NOT NULL,
    rent_start INTEGER NOT NULL,
    rent_end INTEGER NOT NULL,
    personId INTEGER NOT NULL,
    tariff INTEGER NOT NULL,
    PRIMARY KEY carId,
    FOREIGN KEY (personId) REFERENCES Persons(PersonID)
    CONSTRAINT CHK_CR_AVLBL CHECK (dbo.CarCheck(carId , rent_start , rent_end ) = 1))

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

if exists (select * from dbo.CarRentSchedule rt
               where rt.carId = @id 
                 and ((rt.rent_Start >= @startTime and rt.rent_end < @endTime)
                      or  
                      (rt.rent_end <= @endTime and rt.rent_end > @startTime)
                      or 
                      (rt.rent_Start < @endTime and rt.rent_end > @startTime)
                      or 
                      (rt.rent_Start >= @startTime and rt.rent_end <= @endTime)))
        return 0

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

Я проверил, при вызове из ограничения функция, похоже, возвращает NULL, однако при вызове такой функции, как

select dbo.CheckFunc(1, 10, 15, 1, 1) 

, возвращается 0/1, как и предполагалось. Я также проверил и обнаружил, что если в функции нет SELECT (например, простая операция сравнения), то и в этом ограничении она будет работать нормально.

Может кто-нибудь объяснить, почему это работает таким образом? ? Это какое-то ограничение, запрещающее использование SELECT внутри ограничений, или это потому, что SELECT ссылается на ту же таблицу, к которой применено ограничение?

Ответы [ 3 ]

0 голосов
/ 17 февраля 2020

Это отвечает первоначальной версии вопроса.

Ваше первое условие должно быть обработано с ограничением check:

check (occ_end > occ_start)

Затем исправьте лог c, чтобы перекрытия могли Помогите. Я бы предложил:

if exists (select 1
           from dbo.RoomSchedule rs
           where p.roomId = @rn and
                 p.occ_end >= @startTime and 
                 p.occ_start < @endTime
          )

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

0 голосов
/ 17 февраля 2020

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

Итак, да, похоже, я переписал функцию, чтобы она не учитывала вновь добавленную запись и теперь она работает. Странно, но я просто не представляю, что запись, которая в настоящее время тестируется для добавления, будет участвовать в стороне, выбранной из этой таблицы.

0 голосов
/ 17 февраля 2020

Можете ли вы попробовать ниже, если это работает:

Alter function AvailableCar
    (@car integer, @startTime integer, @endTime integer)
returns integer 
as
begin
declare @value int
    set @value = (select max(1) from dbo.CarRentSchedule as rt
               where rt.roomId = @car 
                 and ((rt.rent_Start >= @startTime and p.occ_start < @endTime)
                      or  
                      (rt.rent_end <= @endTime and rt.rent_end > @startTime)
                      or 
                      (rt.rent_Start < @endTime and rt.rent_end > @startTime)
                      or 
                      (rt.rent_Start >= @startTime and rt.rent_end <= @endTime)))
       if (@value is NULL)
       set @value = 0

       return @value


end
...