2011-02-23 88 views
2

这是一个复杂的情况,我是ain。我有预订房间的预订系统。计算预定义日期范围内的天数

事情是房间的价格不是作为一个单一的价值储存,而是以期间为基础。就像一个房间可以在九月到十二月之间有一个每日房价,并且在三月到八月之间可以有一个不同的房价,而另一个房间的基本房价则可以。

率表是这样的:

ROOMID | RATE | PERIOD_START | PERIOD_END 

让我们假设对于到3月31日3月1日之间的房,价格为20元/天,并于5月30日同处一室,从4月15日率是30美元,不过这个比率是15美元/天的统一费率。

如果这个房间是由一个客户端3月15日之间预订到5月10日,总成本将是:

15th March - 31st march charged at 20 Dollars/day = 16x20 
1st April - 14th April charged at 15 Dollars/day = 14x15 
15th April - 10th May charged at 30 Dollars/day = 25x30 

现在我该怎么计算代码这个值,我会需要计算数量写天基于费率周期(如果有的话),否则使用基准费率。它的复杂,但它是如何。我正在使用php MySQL

+0

[SQL要检查一组日期是否在指定的日期范围内](http://stackoverflow.com/questions/5027119/sql-to-check-if-a-set-of-日期 - 落在指定范围内的日期)[或者,也许这个](http://stackoverflow.com/questions/5092028/need-to-see-if-a-range-of-dates-重叠 - 另一个日期范围内的SQL) – 2011-02-23 17:53:10

+0

所以问题是,有些日子要被预订可能在不同的价格/日期范围?那么就像3月31日之前的3天,然后4月1日之后的两天? – Jonah 2011-02-23 18:00:07

+0

@jonah - yep就像你放的那样 – Ali 2011-02-23 18:04:52

回答

2

这是一种可能的解决方案的算法:

  1. 找到具有与(1)中,计算所找到的每个速率周期的预订期间
  2. 非空交集所有速率周期与预订期限相交的天数,并乘以期间费率
  3. 剩余天数(即以天为单位的预订期限减去(2)中找到的所有天数之和即为您的基本费率天数

的Re(1),以便找到哪个速率周期相交预订期间,请注意,2个间隔(A,B)(C,D)有一个空交集IFF D < A or C > B,这样可以只是否定该条件。应该是这个样子:

SELECT * FROM rates 
    WHERE NOT (booking_end < period_start OR 
       booking_start > period_end) 

回复(2),你只需要找到max(booking_start, period_start)min(booking_end, period_end),(含)之间的天数。我确信有公用事业来处理日期,但最坏的情况下,你可以循环。

很抱歉,但我不是一个SQL/PHP的向导来编写实际的代码... :)

1

一个可能的解决方案是有一个名为price_periods的表格,其中包含开始日期,结束日期和价格以及对房间的引用。

所以SQL表看起来像这样。

PRICE_PERIODS

PPID | ROOM_ID | PP_START_DATE | PP_END_DATE | PP_PRICE 
------------------------------------------------------- 
1  2   09-20   10-20   15 
2  2   10-21   11-20   20 

,那么只需在计算具体日期预订已通过取得,因此假设该人想租从10-11一个房间里,直到10-25,他将不得不支付对于ID为1的PRICE_PERIOD,直到PP_END_DATE发生,然后用ID 2支付PRICE_PERIOD,直到预订结束。所以事情是,你可能会有两个以上的日期在任何时候工作。

我想你的预订表看起来像这样。

BOOKINGS

B_ID | ROOM_ID | USER_ID | START_DATE | END_DATE 
------------------------------------------------ 
1  2   4   10-11  10-25 

你将不得不作出的计算,但有一个开始,将可能工作。

1

试试这个。

这将循环显示在预订时间段内的每一天,从表中找到适当的速率,然后将其添加到总计中。

$Day="2011-03-15"; 
$End="2011-05-10"; 
$Periods=array(); // Filled with the Mysql rows - mysql_fetch_assoc() 
$Total=0; 

EDIT

更多优化。

foreach($Periods as $Period) { 
    if($Day>=$Period['PERIOD_START']&&$Day<=$Period['PERIOD_END']) { 
     while($Day<=$End&&$Day<=$Period['PERIOD_END']) { 
      $Total+=$Period['RATE']; 
      $Day=date('Y-m-d',strtotime("$Day +1 day")); 
     } 
    } 
} 
+0

If你想优化它,你并不需要在每次迭代中逐步完成每个周期。只要保持排序的时间段,并且当您经过当前时间段时,切换到下一个时段。如果'$ < $period->开始',您将知道是否处于期间($ 10)之间。 – Matthew 2011-02-23 22:26:47

+0

通过将Periods循环放在顶部来更好地进行优化。这减少了整个不必要的循环。 – 2011-02-23 22:56:59

1

只有半认真的回答在这里。

如果你想要一个SQL查询,你可以这样做:

SELECT SUM(IF(ISNULL(r.rate), 10, r.rate)) 
FROM days AS d 
LEFT JOIN rates AS r ON d.d BETWEEN r.start AND r.end 
    WHERE d.d BETWEEN '2011-03-15' and '2011-05-10'; 

的技巧是,你需要一个所谓的“天”,有一个单独的日期字段d表。预先填充该表格以便从现在开始直到永恒。通过脚本很容易做到;你只需要在那里保留未来的可预约日期。

请注意,您必须小心如何选择开始日期和结束日期。例如,如果您在3月31日至4月1日之间预订了房间,那究竟意味着什么?

这是一个20美元的日子和一个10美元的日子吗?或者只有20美元一天?还是单日10美元?

它本质上并不影响这个答案,但它确实会影响您建立费率表的方式以及您用作启动和停止的日期。

此外,此版本假定rates字段使用完整的YYYY-MM-DD格式。这不是绝对的要求,但如果它只是MM-DD,那么你必须稍微修改连接。

个人而言,我不会这样做。相反,我只是在使用DateInterval类的PHP代码中循环使用这些日子,并以这种方式查询价格。