我必须实现一个解决方案,其中两个日期范围可以相互重叠。在重叠日期内,我必须计算彼此重叠的天数。一旦我知道重叠的天数,我就可以根据每天附加的价格计算总数。
一种情况是
客户正在预订酒店
客户预订日期 - 17/02/2011至26/02/2011
正常价格(全年) - 01/01/2011 - 2011年12月31日(每日价格:$ 30.00)
特别优惠1日期 - 2011年1月1日至2011年2月19日(每日价格:$ 20.00)
特别优惠2日期 - 2011年2月17日至24/02/2011(每日价格:10.00美元)
在上面的场景中,建议的算法应该计算出日期范围重叠的最便宜的报价并计算出预订的价格。如果没有可用的特别优惠,则使用正常价格。
因此,前两天系统应该从“特价1”中获得价格,因为它是最便宜的价格。接下来的5天应该是“特价2价”,接下来的2天就是正常价格。
我很高兴看到SQL(使用MS-SQL Server)或Code base答案来获取diffrenet视图。
我希望这个问题很明确,并希望看到答案。
非常感谢提前
答案 0 :(得分:1)
使用auxiliary calendar table的标准技巧,只是加入和分组的情况,每天都能获得最优惠的价格:
SELECT C.dt, MIN(price) AS best_price
FROM Prices P
INNER JOIN Calendar C
ON C.dt >= P.price_start_date
AND C.dt < P.price_end_date
INNER JOIN CustomerBooking B
ON C.dt >= B.booking_start_date
AND C.dt < B.booking_end_date
GROUP
BY C.dt;
与上述相同的查询,包括使用CTE的样本数据:
WITH Prices (price_start_date, price_end_date, narrative, price)
AS
(
SELECT CAST(start_date AS Date), CAST(end_date AS Date), narrative, price
FROM (
VALUES ('2011-01-01T00:00:00', '2011-12-31T00:00:00', 'Normal price', 30),
('2011-01-01T00:00:00', '2011-02-21T00:00:00', 'Special Offer 1', 20),
('2011-02-19T00:00:00', '2011-02-24T00:00:00', 'Special Offer 2', 10)
) AS T (start_date, end_date, narrative, price)
),
CustomerBooking (booking_start_date, booking_end_date)
AS
(
SELECT CAST(start_date AS Date), CAST(end_date AS Date)
FROM (
VALUES ('2011-02-17T00:00:00', '2011-02-26T00:00:00')
) AS T (start_date, end_date)
)
SELECT C.dt, MIN(price) AS best_price
FROM Prices P
INNER JOIN Calendar C
ON C.dt >= P.price_start_date
AND C.dt < P.price_end_date
INNER JOIN CustomerBooking B
ON C.dt >= B.booking_start_date
AND C.dt < B.booking_end_date
GROUP
BY C.dt;
答案 1 :(得分:0)
我们假设您应该每天申请最低价格。
create function price ( @fromDate date, @toDate date) returns money
as
begin
declare @iterator_day date
declare @total money
set @total = 0
set @iterator_day = @fromDate
WHILE @iterator_day < = @toDate
begin
select @total = @total + min( price )
from offers
where @iterator_day between offers.fromFay and offers.toDay
set @iterator_day = DATEADD (day , 1 , @iterator_day )
end
return @total
end
然后你可以在你的查询中调用函数:
select
b.fromDay, b.toDay, dbo.price( b.fromDay, b.toDay )
from
booking b
答案 2 :(得分:0)
我只使用过ASP.net 4.0,但我可以提供一些SQL,它会给你一个给定日期的价格:
SELECT ISNULL(MIN(PricePerDay), 0) AS MinPricePerDay
FROM Offers
WHERE (StartDate <= '18/2/11') AND (EndDate >= '18/2/11')
从您的应用程序中,您可以构建如下所示的查询:
SELECT ISNULL(MIN(PricePerDay), 0) AS MinPricePerDay
FROM Offers
WHERE (StartDate <= '17/2/11') AND (EndDate >= '17/2/11');
SELECT ISNULL(MIN(PricePerDay), 0) AS MinPricePerDay
FROM Offers
WHERE (StartDate <= '18/2/11') AND (EndDate >= '18/2/11');
SELECT ISNULL(MIN(PricePerDay), 0) AS MinPricePerDay
FROM Offers
WHERE (StartDate <= '19/2/11') AND (EndDate >= '19/2/11');
这将返回一个表的数据集,其中包含该日期最低价格的单个值(与查询的顺序相同)
对于Stored Procedure ...
来说,这听起来不错答案 3 :(得分:0)
您的问题是,您有多个重叠的时间段。您需要稍微约束问题,或稍微重新构建数据。 (获得理想的表现。)
选项1 - 约束
最后一个约束是最奇怪的。但它需要使简单的连接工作。比较日期范围时,如果两组范围无间隙且内部没有重叠,则 更容易形成查询。
这意味着您现在应该可以通过几个连接来解决这个问题......
SELECT
CASE WHEN [sp].started > [np].started THEN [sp].started ELSE [np].started END AS [started]
CASE WHEN [sp].expired < [np].expired THEN [sp].expired ELSE [np].expired END AS [expired]
CASE WHEN [sp].price < [np].price THEN [sp].price ELSE [np].price END AS [price]
FROM
normal_prices AS [np]
LEFT JOIN
special_prices AS [sp]
ON [sp].started < [np].expired
AND [sp].expired > [np].started
AND [sp].started >= (SELECT ISNULL(MAX(started),0) FROM special_prices WHERE started <= [np].started)
-- The third condition is an optimisation for large data-sets.
WHERE
[np].started < @expired
AND [np].expired > @started
-- Note: Inclusive StartDates, Exlusive EndDate
-- For example, "all of Jan" would be "2011-01-01" to "2011-02-01"
选项2 - 重新建模
这个经常是我经历中最快的;你增加了使用的空间量,并获得更简单的查询...
Table Of Prices, stored by DAY rather than period...
- calendar_date
- price_code
- price
SELECT
calendar_date,
MIN(price)
FROM
prices
WHERE
calendar_date >= @started
AND calendar_date < @expired
或者,如果您还需要price_code ......
WITH
ordered_prices AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY calendar_date ORDER BY price ASC, price_code) AS price_rank,
*
FROM
prices
)
SELECT
calendar_date,
price_code,
price
FROM
ordered_prices
WHERE
calendar_date >= @started
AND calendar_date < @expired