永远不会满足包含 Select 的函数约束

A constraint with function that contains Select is never satisfied

我有一个 table 这样的:

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))

并且我需要禁止同一辆车在任何租用时间交叉口。 我发现,当在约束内使用函数(如下示例)时,它的值 returns 与在约束外使用时不同。

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

因此,当我尝试将数据插入 table 时,由于某些原因,约束永远不允许我这样做。

我已经检查过,当从约束中调用函数时,函数似乎 return NULL,但是调用函数时

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

会 return 0/1,因为它应该是。我还检查并发现,如果函数中没有 SELECT(例如,一个简单的比较操作),它在约束中也能正常工作。

谁能解释一下为什么会这样?是禁止在约束内使用 SELECT 还是因为 SELECT 引用了相同的 table 约束?

如果可行,你可以试试下面的方法吗:

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

这回答了问题的原始版本。

你的第一个条件应该用 check 约束来处理:

check (occ_end > occ_start)

那么,正确的重叠逻辑可能会有所帮助。我会建议:

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

如果第一个在第二个结束之前开始并且第一个在第一个开始之后结束,则两个时间段重叠。

My guess is that when checking the second constraint the new enty is already considered to be a part of the table so it always overlaps with itself. But this is seems strainge, doesn't it?

所以,是的,它看起来是这样,我已经重新编写了函数,这样它就不会考虑新添加的条目,现在它可以工作了。很奇怪,不过,我只是无法想象当前正在测试要添加的条目会从 table.

参与 select 方面