3

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

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

业务规则如下

  1. 如果dateFromdateTo在同一天,则认为是 1 天
  2. 如果预订是从那时起2013-05-252013-06-06那么 7 天到 5 月,5 天到 6 月 这里是这个逻辑的分解
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用于数据测试

4

2 回答 2

1

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

如果您正在查找整个历史记录,您当然可以总结每个预订的各个长度。你想要一些每月的细分吗?

SELECT SUM( TO_DAYS(dateTo)-TO_DAYS(dateFrom) +1 ) AS sum_days_reserved FROM table
于 2013-07-07T19:05:55.797 回答
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小提琴

您必须考虑的最重要的事情是日期范围是包含还是不包含。因此,如果您想要从 5/31 到 6/1 的金额,这是否意味着您想要包括 6/1 的收入,或者这是否意味着您只寻找 5/31 的收入。这个概念让很多开发人员感到困惑。从您的评论和帖子中,我假设您希望日期范围是专有的。

在我创建的情况下,窗口从 00:00:00 的 5/31 到 00:00 的 6/1。如果您希望它具有包容性,您可以在 6/2 00:00:00 结束窗口。

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

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

于 2013-07-14T17:29:54.343 回答