与票价重叠的日期

时间:2013-01-26 09:34:34

标签: php mysql

我有这个问题:

SELECT  price.car_number1, car_from, car_to, car_fares
FROM    price, car
WHERE   car.car_number1 = price.car_number1

输出如下:

car_number1    car_from     car_date      car_fare
------------------------------------------------------
BAL2018        2013-01-21   2013-01-26    $555         
BAL2018        2013-01-27   2013-01-28    $111
BAL2019        2013-01-26   2013-01-27    $211 
BAL2020        2013-01-26   2013-01-27    $545

现在假设使用想要从2013-01-212013-01-28的费率的UI结果,我想以某种或其他方式打印每辆车的价格以用于各自的日期并且如果汽车没有分配的票价应显示为N/A

请告诉我,无论如何我可以在mysql或任何PHP中执行此操作

我想让它看起来像(例如)

           01-21   01-22 01-23 01-24 01-25  01-26 01-27 01-28 
 BAL2018   $555    $555  $555  $555  $555   $555  $111  $111
 BAL2019   N/A     N/A   N/A   N/A   N/A    $211  $211  N/A

3 个答案:

答案 0 :(得分:0)

只是在没有实际数据的情况下猜测,但这样的事情呢?

SELECT  car.car_number1, car.car_from, car.car_to, 
            ifnull(price.car_fares,'N/A') as car_fare
FROM    car left join price ON car.car_number1=price.car_number1
WHERE   car.car_from >= '2013-01-21' and car.car_to < '2013-01-28'

我假设car_fares字段在price表中,而所有其他字段都在car表中。

答案 1 :(得分:0)

最好的妥协,恕我直言,将选择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。

这可能看起来很挑剔,直到你因为leap second而在7月(或6月份?)失去了15个酒店房间预订。这不是我的代码,但我是那个必须进行扫视的人。

另一个问题是,如果你有一个CAR_FROM为“1月1日”和CAR_TO “12月31日”,你想要3月21日至28日的价格,然后是那一排 即使没有行指定3月份的日期,也是相关的。所以你需要处理重叠。

最后,您可能会有一个从2013年1月1日到2013年12月31日的条目,之后您可能会有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;
?>

答案 2 :(得分:0)

在下面的示例中,calendar是一个简单的实用程序表,其中包含可能需要的所有日期。就个人而言,我最有可能处理缺失的值,当然还有应用程序级的转向,以便于扩展。

DROP TABLE IF EXISTS fares;

CREATE TABLE fares
( vehicle_id VARCHAR(12) NOT NULL 
, fare_start DATE NOT NULL
, fare_end DATE NULL
, fare DECIMAL(5,2) NOT NULL 
, PRIMARY KEY(vehicle_id,fare_start)
);

INSERT INTO fares VALUES 
('BAL2018','2013-01-21','2013-01-26',555.00),
('BAL2018','2013-01-27','2013-01-28',111.00),
('BAL2019','2013-01-26','2013-01-27',211.00), 
('BAL2020','2013-01-26','2013-01-27',545.00);

DROP TABLE IF EXISTS vehicles;

CREATE TABLE vehicles
(vehicle_id VARCHAR(12) NOT NULL PRIMARY KEY
,description VARCHAR(12) NOT NULL
);

INSERT INTO vehicles VALUES 
('BAL2018','vehicle01'),
('BAL2019','vehicle02'),
('BAL2020','vehicle03');

SELECT * FROM calendar WHERE dt BETWEEN '2013-01-20' AND '2013-01-28';
+------------+
| dt         |
+------------+
| 2013-01-20 |
| 2013-01-21 |
| 2013-01-22 |
| 2013-01-23 |
| 2013-01-24 |
| 2013-01-25 |
| 2013-01-26 |
| 2013-01-27 |
| 2013-01-28 |
+------------+

 SELECT c.dt,v.vehicle_id,f.fare_start,f.fare_end,f.fare FROM calendar c
   JOIN vehicles v
   LEFT
   JOIN fares f
     ON f.vehicle_id = v.vehicle_id
    AND c.dt BETWEEN f.fare_start AND f.fare_end
  WHERE c.dt BETWEEN '2013-01-20' AND '2013-01-28';
+------------+------------+------------+------------+--------+
| dt         | vehicle_id | fare_start | fare_end   | fare   |
+------------+------------+------------+------------+--------+
| 2013-01-20 | BAL2018    | NULL       | NULL       |   NULL |
| 2013-01-20 | BAL2019    | NULL       | NULL       |   NULL |
| 2013-01-20 | BAL2020    | NULL       | NULL       |   NULL |
| 2013-01-21 | BAL2018    | 2013-01-21 | 2013-01-26 | 555.00 |
| 2013-01-21 | BAL2019    | NULL       | NULL       |   NULL |
| 2013-01-21 | BAL2020    | NULL       | NULL       |   NULL |
| 2013-01-22 | BAL2018    | 2013-01-21 | 2013-01-26 | 555.00 |
| 2013-01-22 | BAL2019    | NULL       | NULL       |   NULL |
| 2013-01-22 | BAL2020    | NULL       | NULL       |   NULL |
| 2013-01-23 | BAL2018    | 2013-01-21 | 2013-01-26 | 555.00 |
| 2013-01-23 | BAL2019    | NULL       | NULL       |   NULL |
| 2013-01-23 | BAL2020    | NULL       | NULL       |   NULL |
| 2013-01-24 | BAL2018    | 2013-01-21 | 2013-01-26 | 555.00 |
| 2013-01-24 | BAL2019    | NULL       | NULL       |   NULL |
| 2013-01-24 | BAL2020    | NULL       | NULL       |   NULL |
| 2013-01-25 | BAL2018    | 2013-01-21 | 2013-01-26 | 555.00 |
| 2013-01-25 | BAL2019    | NULL       | NULL       |   NULL |
| 2013-01-25 | BAL2020    | NULL       | NULL       |   NULL |
| 2013-01-26 | BAL2018    | 2013-01-21 | 2013-01-26 | 555.00 |
| 2013-01-26 | BAL2019    | 2013-01-26 | 2013-01-27 | 211.00 |
| 2013-01-26 | BAL2020    | 2013-01-26 | 2013-01-27 | 545.00 |
| 2013-01-27 | BAL2018    | 2013-01-27 | 2013-01-28 | 111.00 |
| 2013-01-27 | BAL2019    | 2013-01-26 | 2013-01-27 | 211.00 |
| 2013-01-27 | BAL2020    | 2013-01-26 | 2013-01-27 | 545.00 |
| 2013-01-28 | BAL2018    | 2013-01-27 | 2013-01-28 | 111.00 |
| 2013-01-28 | BAL2019    | NULL       | NULL       |   NULL |
| 2013-01-28 | BAL2020    | NULL       | NULL       |   NULL |
+------------+------------+------------+------------+--------+

27行(0.00秒)