恕我直言,最好的折衷方案是在 MySQL 中选择日期范围,然后使用 PHP 提供任何缺失的信息。
请原谅我可能过于挑剔,但有一次我被以下所有问题所困扰,所以我将为一个看似简单的问题提供一个显然复杂的解决方案:-)
日期选择算法可能会出现一个问题,因为“第二天”并不是人们想象的那么明确的表达方式——当切换夏令时时,有些日子是 23 小时或 25 小时,有些日子有额外的一秒钟,以便 $ts += 86400 将您从 D:M:Y 00:00:00 带到 D:M:Y 23:59:59 而不是 D+1:M:Y 00:00:00。
直到您在 7 月(或者是 6 月?)因为闰秒而失去 15 个酒店房间预订之前,这似乎很挑剔。这不是我的代码,但我是必须进行清理的人。
另一个问题是,如果您有“1 月 1 日”的 CAR_FROM 和“12 月 31 日”的 CAR_TO,并且您想要 3 月 21 日至 28 日之间的价格,那么该行将是相关的,即使没有行指定 3 月的日期. 所以你需要注意重叠。
最后,您可能有一个从 1-1-2013 到 31-12-2013 的条目,然后您可能有一个从 2013 年 5 月 1 日到 2013 年 5 月 17 日的条目,并且您希望第二个条目优先于5 月 1 日至 17 日的范围。实际上,如果客户改变主意,您需要一种快速从一个优先系统选择到另一个系统的方法。
所以你可以这样做:
<?php
$start = mktime(12, 0, 0, $month1, $day1, $year1);
$stop = mktime(12, 0, 0, $month2, $day2, $year2);
$DATE_FORMAT = 'd-m-Y'; // This might be a define, actually
// Use these dates in MySQL query. This takes care
// of most date problems.
$SQL_From = date('Ymd000000', $start);
$SQL_To = date('Ymd235959', $stop);
// We create a date array initialized with N/A, and use
// a date format as a key
$empty = array();
for ($ts = $start; $ts <= $stop; $ts += 86400)
{
$date = date($DATE_FORMAT, $ts);
$empty[$date] = 'N/A';
}
/*
To select dates overlapping [FROM-TO], consider that we do NOT want
a date when its TO is less than our FROM of interest:
[from -- car -- to] [FROM TO]
and neither when its from is more than our TO of interest:
[FROM TO] [from -- car -- to]
So we want all dates except those, and this means
WHERE NOT ( car_to < SQL_From OR car_from > SQL_To)
But since NOT (A OR B) is logically equal to A AND B, we get this
not very intuitive, but very efficient query
$query = ...
SELECT price.car_number1, car_from, car_to, car_fares
FROM price JOIN car ON car.car_number1 = price.car_number1
WHERE car_from < $SQL_To AND car_to > $SQL_From
ORDER BY car_number1, car_from;
The precedence is given by car_from: later dates win over earlier dates.
But you might have a PRIORITY field that overrides all, so that PRIORITY=0
means normal and PRIORITY 99 means "THESE are the prices, damn your eyes!";
to achieve that, you can now simply "ORDER BY car_number1,priority,car_from."
*/
$cars = array();
// Now we retrieve all car data, with PDO or whatever
while($tuple = SQLFetchRow(...))
{
// If this is a new car, we initialize its array to all N/A
if (!isset($cars[$tuple['car_number1']))
$prices = $empty;
else
$prices = $cars[$tuple['car_number1'];
// Now we check our tuple and see what prices have changed
// MySQL retrieves date in Y-M-D format
list($y,$m,$d) = explode('-', $tuple['car_from']);
$from = mktime(12, 0, 0, $m, $d, $y);
list($y,$m,$d) = explode('-', $tuple['car_to']);
$to = mktime(12, 0, 0, $m, $d, $y);
// This will overwrite any existing data with fresher data
for ($ts = $from; $ts <= $to; $ts += 86400)
{
$date = date($DATE_FORMAT, $ts);
$prices[$date] = $tuple['car_fare'];
}
// Now we save the modified array into $cars.
$cars[$tuple['car_number1'] = $prices;
}
// And finally we print the results into a variable,
// so it will be easier to wrap this into a helper function.
$row = '<tr>';
$row .= '<th>-</th>';
foreach($empty as $date => $dummy)
$row = '<th>'.$date.'</th>';
$row .= '</tr>';
$table = '<table>' . $row;
foreach($cars as $plate => $prices)
{
$row = '<tr><td>'.$plate.'</td>';
foreach($prices as $dummy_date => $price)
$row .= '<td>'.$price.'</td>';
$row .= '</tr>';
$table .= $row;
}
$table .= '</table>';
print $table;
?>