我有一张预订表。每行都是预订,并且有一个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-01
到2018-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
答案 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
函数来截断TIME
和StartDate
的之间的某些引擎盖的原因我并不完全熟悉。EndDate
部分,例如,2018-04-01
表示一整天,它不能介于2018-04-01 09:00:00
和2018-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'
会产生1
(TRUE
)。默认DATE
似乎TIMESTAMP
为00:00:00
。
上面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个数字。
我假设您的存储过程或某个地方会有StartDate
和EndDate
。我们可以将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