我有一个经过日期范围的存储过程,并且对于每个日期,查找在该日期未预订的可预订对象。我正在努力寻找一种方法,从使用while循环和临时表的功能存储过程转换为使用更高效的东西:
declare @from datetime
declare @to datetime
declare @currentdate datetime
declare @hotelid int
set @from = '2018-06-14 17:00'
set @to = '2019-06-25 14:00'
set @currentdate = DATEADD(dd, DATEDIFF(dd, 0, @from), 0)
set @hotelid = 2
Create table dbo.#AvailableObjectsDateRange
(
Date datetime not null,
Name nvarchar(max) not null,
ObjectId bigint not null,
ProductId bigint not null,
ParentProductId bigint null
)
WHILE (@currentdate < DATEADD(dd, DATEDIFF(dd, 0, @to), 0))
BEGIN
;with Reserved as (select bookableobjectid from hotell.BookingRows as br
join hotell.bookings as b on br.bookingid = b.Id
where b.HotelId = @hotelid and br.bookedto > DateAdd(dd, 1, @currentdate) and
br.bookedfrom < DateAdd(dd, 1, @currentdate) and br.checkedout = 0
and (br.isactive = 1 and b.IsActive = 1))
insert into #AvailableObjectsDateRange select @currentdate, bo.Name, bo.Id,
p.Id, p.ParentId from hotell.BookableObjects as bo
join hotell.products as p on bo.ProductId = p.Id
where bo.hotelid = @hotelid
and UnactivatedAt is null
and p.isaddon = 0
and bo.isactive = 1
and bo.id not in (select * from reserved)
SET @CurrentDate = DATEADD(DAY, 1, @CurrentDate); /*increment current date*/
END
select * from #AvailableObjectsDateRange order by Date
drop table #AvailableObjectsDateRange
它的表现对我们的情况来说没问题,但它可能会有很大改善。
答案 0 :(得分:2)
看起来你正在填充一个表格,该表格在该范围内的每一天都有一行,并且每个“对象”(酒店?房间?)都没有为那天保留。正确的吗?
最好和最快的方法是完全基于。为此,您需要一个日历表(谷歌)和一个所有对象的表。然后,查询本身只是这两个表之间的交叉连接,带有NOT EXISTS以排除保留对象。像(未经测试的伪代码):
INSERT INTO dbo.#AvailableObjectsDateRange (column list)
SELECT column list
FROM dbo.Calendar AS c
CROSS JOIN dbo.ObjectList AS o
WHERE c.Date >= @from
AND c.Date < @to
AND NOT EXISTS
(SELECT *
FROM bookings AS b
WHERE c.Date >= b.bookingfrom
AND c.Date < b.bookingto
AND c.ObjectID = o.ObjectID);
您可能需要稍微调整日期逻辑,并在代码中添加特定的额外内容。
编辑:在回复你的评论时:你必须用你的实际逻辑替换子查询来获得所有预订。与您在问题中的CTE中的内容类似。我不想在答案中重复这一点,因为我想专注于逻辑结构:与对象交叉连接日期(在范围内),然后排除那些保留的< / p>