如何计算MySQL中预留的总天数

时间:2013-07-07 18:57:25

标签: mysql

我有一张表,商店车辆预订每张记录dateFrom“预订开始日期”和dateTo“预订结束日期”

我正在尝试编写一个查询来计算每辆车预订的总天数以及每辆车产生的总收入。

业务规则如下

  1. 如果dateFromdateTo在同一天,则认为是1天
  2. 如果预订的时间是2013-05-252013-06-06,那么7天到5月份就会有5天到6月份就是这个逻辑的分解
  3. 2013-05-25 - 2013-05-26 (May)
    2013-05-26 - 2013-05-27 (May)
    2013-05-27 - 2013-05-28 (May)
    2013-05-28 - 2013-05-29 (May)
    2013-05-29 - 2013-05-30 (May)
    2013-05-30 - 2013-05-31 (May)
    2013-05-31 - 2013-06-01 (**May**)
    2013-06-01 - 2013-06-02 (June)
    2013-06-02 - 2013-06-02 (June)
    2013-06-03 - 2013-06-02 (June)
    2013-06-04 - 2013-06-02 (June)
    2013-06-05 - 2013-06-02 (June)
    

    这是一个关于计算应如何运作的例子。

    对于收入,我想通过将总收入除以总租用天数来计算平均每日租金,然后将每日平均值乘以适合此范围的总天数

    这是我当前的查询,但它没有正确计算今天的日期。 所以在上面的例子中我们假设整个预订的总收入是1500美元 那么平均每日租金为$1500/12 = $125

    因此,由于我们计算的范围为"2013-06-01 00:00:00""2013-06-16 23:59:59",因此此车辆的总天数应为5天,总收入为625美元。 更多信息,如果范围是2013-05-01 00:00:002013-05-31 23:59:59,则同一车辆总共需要7天,总收入为875美元

    以下是我当前的查询,我试图计算差异。

    SELECT rs.vehicle_id,
        ROUND(SUM(
    
    
            CASE
            WHEN (rs.dateFrom BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59")
            AND (rs.dateTo BETWEEN "2013-06-01 00:00:00"  AND "2013-06-16 23:59:59")
            THEN (rs.totalRent + rs.totalTax)
    
            WHEN rs.dateTo BETWEEN "2013-06-01 00:00:00"  AND "2013-06-16 23:59:59"
            AND rs.dateFrom < "2013-06-01 00:00:00"
            THEN ( ( (rs.totalRent + rs.totalTax) / CASE WHEN DATEDIFF( rs.dateTo,rs.dateFrom) = 0 THEN 1 ELSE DATEDIFF( rs.dateTo,rs.dateFrom) END) * (DATEDIFF(rs.dateTo, "2013-06-01 00:00:00")) )
    
            WHEN rs.dateFrom BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59"
            AND rs.dateTo > "2013-06-16 23:59:59"
            THEN ( ( (rs.totalRent + rs.totalTax) / CASE WHEN DATEDIFF( rs.dateTo,rs.dateFrom) = 0 THEN 1 ELSE DATEDIFF( rs.dateTo,rs.dateFrom) END) * (DATEDIFF( "2013-06-16 23:59:59",rs.dateFrom)+1) )
    
            WHEN rs.dateFrom < "2013-06-01 00:00:00" AND rs.dateTo > "2013-06-16 23:59:59"
            THEN ( ( (rs.totalRent + rs.totalTax) / CASE WHEN DATEDIFF( rs.dateTo,rs.dateFrom) = 0 THEN 1 ELSE DATEDIFF( rs.dateTo,rs.dateFrom) END) * (DATEDIFF( "2013-06-16 23:59:59", "2013-06-01 00:00:00") +1) )
    
            ELSE 0 END 
    
     )) AS income,
    
    
    SUM(
    
            CASE
            WHEN (rs.dateFrom BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59")
            AND (rs.dateTo BETWEEN "2013-06-01 00:00:00"  AND "2013-06-16 23:59:59")
            THEN CASE WHEN DATEDIFF( rs.dateTo,rs.dateFrom) = 0 THEN 1 ELSE DATEDIFF( rs.dateTo,rs.dateFrom) END
    
            WHEN rs.dateTo BETWEEN "2013-06-01 00:00:00"  AND "2013-06-16 23:59:59"
            AND rs.dateFrom < "2013-06-01 00:00:00"
            THEN CASE WHEN DATEDIFF(rs.dateTo, "2013-06-01 00:00:00") = 0 THEN 1 ELSE (DATEDIFF(rs.dateTo, "2013-06-01 00:00:00")) END
    
            WHEN rs.dateFrom BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59"
            AND rs.dateTo > "2013-06-16 23:59:59"
            THEN CASE WHEN DATEDIFF( "2013-06-16 23:59:59",rs.dateFrom) = 0 THEN 1 ELSE (DATEDIFF( "2013-06-16 23:59:59",rs.dateFrom))  END
    
            WHEN rs.dateFrom < "2013-06-01 00:00:00" AND rs.dateTo > "2013-06-16 23:59:59"
            THEN DATEDIFF( "2013-06-16 23:59:59", "2013-06-01 00:00:00")+1 
    
            ELSE 0 END 
    
     ) AS days       
    FROM reservation AS rs
    WHERE rs.reservationStatus IN (2,3)
    GROUP BY rs.Vehicle_id
    

    问题是查询没有正确计算总天数。有人可以帮帮我吗?

    以下是我的代码示例

    http://sqlfiddle.com/#!2/f6cbc/3用于测试数据

2 个答案:

答案 0 :(得分:1)

间隔没有重叠(即对于汽车你有一些逻辑,以确保它不被多次保留?

如果您正在寻找整个历史,您当然可以总结每个预订的剩余长度。你想要每月进行一次细分吗?

SELECT SUM( TO_DAYS(dateTo)-TO_DAYS(dateFrom) +1 ) AS sum_days_reserved FROM table

答案 1 :(得分:1)

所以我对它进行了尝试。我们从代码开始吧。稍后会有解释。

SELECT rs.vehicle_id,
  round(sum(datediff(least(rs.dateTo, '2013-06-02 00:00:00'),
                 greatest(rs.dateFrom, '2013-05-31 00:00:00'))*(totalRent + totalTax)*datediff(least(rs.dateTo, '2013-06-02 00:00:00'),
                 greatest(rs.dateFrom, '2013-05-31 00:00:00'))/totalDays))
        AS income,
  sum(datediff(least(rs.dateTo, '2013-06-02 00:00:00'),
                 greatest(rs.dateFrom, '2013-05-31 00:00:00')))
        AS days
FROM reservation rs
  WHERE rs.dateFrom < '2013-06-02 00:00:00'
    AND rs.dateTo > '2013-05-31 00:00:00'
GROUP BY rs.vehicle_id;

SQL Fiddle

您必须考虑的最重要的事情是日期范围是包含还是排他。因此,如果您希望金额从5/31到6/1,这是否意味着您希望包含6/1的收入,或者这是否意味着您只需要在5月31日查找收入。这个概念让许多开发人员兴奋不已。根据您的评论和帖子,我假设您希望日期范围是独占的。

在我创建的情况下,窗口从5月31日00:00:00到6点00:00。如果你想要它是包容性的,你可以在6/2 00:00:00结束窗口。

解决方案的其余部分只是更优雅的方式来做你已经在做的事情。您可以通过查看开始日期是否小于日期范围的结尾以及结束日期是否大于日期范围的开头来查找日期窗口。

然后,您可以通过查看dateFrom和windowStart的最大值以及dateTo和windowEnd的最小值来计算窗口中的实际天数。