使用日期范围(经典ASP和SQL)

时间:2011-12-01 10:04:00

标签: asp.net sql asp-classic vbscript

我必须实现一个解决方案,其中两个日期范围可以相互重叠。在重叠日期内,我必须计算彼此重叠的天数。一旦我知道重叠的天数,我就可以根据每天附加的价格计算总数。

一种情况是

客户正在预订酒店

客户预订日期 - 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视图。

我希望这个问题很明确,并希望看到答案。

非常感谢提前

4 个答案:

答案 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 - 约束

  • 正常的数据集&#39;价格 - 从不相互重叠
  • &#39;特殊&#39;的数据集。价格 - 也不会相互重叠
  • 每个可预订的日期都有正常的日期&#39;价
  • 每个可预订日期都有一个特殊的日期&#39;价格(如果它是“空”意味着“没有特殊价格&#39;”)

最后一个约束是最奇怪的。但它需要使简单的连接工作。比较日期范围时,如果两组范围无间隙且内部没有重叠,则 更容易形成查询。

这意味着您现在应该可以通过几个连接来解决这个问题......

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