我有一张这样的桌子:
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引用了约束所应用于的同一张表?
答案 0 :(得分:0)
如果可以的话,您可以尝试以下方法:
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
答案 1 :(得分:0)
这回答了问题的原始版本。
您的第一个条件应使用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
)
如果第一个在第二个结束之前开始,而第一个在第一个开始之后结束,则两个时间段重叠。
答案 2 :(得分:0)
我的猜测是,在检查第二个约束时,新的enty已被视为表的一部分,因此它始终与自身重叠。但这似乎很艰辛,不是吗?
是的,看起来是这样,我重新编写了该函数,以便它不会考虑新添加的条目,并且现在可以正常工作。奇怪,所以,我只是无法想象当前正在测试要添加的条目会参与该表的侧面选择。