计算每天的预订,其中res可能跨越多天并且应该计入每天

时间:2018-04-04 08:31:21

标签: mysql

我有一张预订表。每行都是预订,并且有一个start& end日期时间字段。

我想构建一个查询,它会在一定的时间间隔(例如2018年4月)给出每天预订的计数。

选择给定时间间隔内的所有预订非常简单:

SELECT * FROM reservation 
WHERE start <= '2018-05-01 00:00:00' 
AND end >= '2018-04-01 00:00:00'

然后'麻烦'开始了 我想在间隔中的每一天显示预定的“计数”。但预订可能会持续多天。因此,将它们分组到DAY(start)是不正确的。

我不想单独查询间隔中的每一天,因为这将是服务器密集型的。

有没有办法通过MySQL查询来做到这一点?

示例数据:

id | start               | end 
2  | 2018-04-01 12:00:00 | 2018-04-03 09:00:00
3  | 2018-04-01 09:00:00 | 2018-04-01 11:00:00
4  | 2018-04-06 13:00:00 | 2018-05-20 09:00:00

2018-04-012018-04-06的结果:

2018-04-01 | 2   (2/3)
2018-04-02 | 1   (2)
2018-04-03 | 1   (2)
2018-04-04 | 0
2018-04-05 | 0 
2018-04-06 | 1   (4)

在sqlfiddle中:http://sqlfiddle.com/#!9/e62ffa/2/0

1 个答案:

答案 0 :(得分:2)

首先,我们将重用DBA StackExchange的答案。 (如果需要,您可以使用接受的答案,您只需要为此创建一个专用表。)

我们将使用您需要的条件稍微修改一下查询。

你的情况:

SELECT * FROM reservation 
WHERE start <= '2018-05-01 00:00:00' 
AND end >= '2018-04-01 00:00:00'

来自DBA Stackexchange的修改后的答案:

SELECT date_field
FROM
(
    SELECT
        MAKEDATE(YEAR(NOW()),1) +
        INTERVAL (MONTH(NOW())-1) MONTH +
        INTERVAL daynum DAY date_field
    FROM
    (
        SELECT t * 10 + u daynum
        FROM
            (SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) A,
            (SELECT 0 u UNION SELECT 1 UNION SELECT 2 UNION SELECT 3
            UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
            UNION SELECT 8 UNION SELECT 9) B
        ORDER BY daynum
    ) AA
) AAA
/*WHERE MONTH(date_field) = MONTH(NOW())*/
WHERE date_field BETWEEN '2018-04-01' AND '2018-05-01'

请注意,我只更改了WHERE条款。

现在将该查询用作DERIVED TABLE,我们会使用Reservations添加您的LEFT JOIN表格。

 SELECT D.date_field
  , COUNT(R.Id)
  FROM (
    /* The query from above goes here */
  ) D
  LEFT JOIN Reservations R ON D.date_field BETWEEN DATE(R.StartDate) AND DATE(R.EndDate)
  GROUP BY D.date_field

再次注意,我们使用DATE函数来截断TIMEStartDate EndDate部分,例如,2018-04-01表示一整天,它不能介于2018-04-01 09:00:002018-04-01 11:00:00 之间的某些引擎盖的原因我并不完全熟悉。

以下是结果的SQL Fiddle Demo

如果有人可以帮我这个。 SELECT '2018-04-02' BETWEEN '2018-04-01 23:59:59' AND '2018-04-02 00:00:00'会产生1TRUE)。默认DATE似乎TIMESTAMP00:00:00

更新更灵活的日期范围(2018-04-11)

上面DBA StackExchange的查询仅列出当前月份的日期。我试着搜索一下,找到了another good answer here in StackOverflow。以下是查询的一部分:

SELECT CURDATE() - INTERVAL (A.A+ (10 * B.A)) DAY AS Date
    FROM (
        SELECT 0 AS A UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
        UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
    ) AS A
    CROSS JOIN (
        SELECT 0 AS A UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
        UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
    ) AS B

上面的查询会使用CROSS JOIN生成数字(1到100),然后将其减去Current Date,那么您将拥有从现在起100天之后的日期。如有必要,您可以添加另外CROSS JOIN个数字以生成1000个数字。

我假设您的存储过程或某个地方会有StartDateEndDate。我们可以将CURDATE替换为EndDate,然后我们将有100天时间回到EndDate。我们将添加一个WHERE子句,仅使用子查询/派生表过滤我们需要的日期。

SELECT D.Date
    FROM (
        SELECT CURDATE() - INTERVAL (A.A+ (10 * B.A)) DAY AS Date
            FROM (
                SELECT 0 AS A UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
                UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
            ) AS A
            CROSS JOIN (
                SELECT 0 AS A UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
                UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
            ) AS B
    ) AS D
    WHERE D.Date BETWEEN @startDate AND @endDate

我们现在可以使用LEFT JOIN来包含Reservations表。

这是另一个 SQL Fiddle Demo 。这还包括开始日期和结束日期变量,以及从上一年到当前年份的样本日期范围。

如果您需要超过100天的范围,我们只需添加另外CROSS JOIN个数字,我们将其命名为C

CROSS JOIN (
    SELECT 0 AS A UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
    UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) AS C

然后将其添加到SELECT语句中过去几天的计算中。

SELECT CURDATE() - INTERVAL (A.A + (10 * B.A) + (100 * C.A)) DAY AS Date