MySQL 计算 table 中两个日期之间的星期几
MySQL count day of week between two dates over a table
我的预订 table 包含以下列:
id, start_date, end_date
我想知道在我的数据集中哪几天的预订最多。
我可以在开始日期上使用 dayofweek() 并以此为分组,并使用计数 (*)。但我还想包括预订开始和结束之间的天数。
示例输出为
dayofweek count(*)
1 1
2 1
3 1
4 2
5 3
6 3
7 1
下一组
id start_date end_date
1 2017-10-01 2017-10-07
2 2017-10-04 2017-10-07
3 2017-10-06 2017-10-08
您可以通过递归 table:
WITH cte AS
(
SELECT DATE_ADD(start_date INTERVAL 1 DAY) AS date, end_date, DAYOFWEEK(start_date) AS dw from bookings
UNION ALL
SELECT DATE_ADD(start_date INTERVAL 1 DAY), end_date, DAYOFWEEK(date)
FROM cte WHERE date <= end_date
)
SELECT COUNT(*), dw FROM cte GROUP BY dw
我假设您希望知道从开始到结束期间每个日期有多少房间已入住。这里的"trick" 是start/end 之间的长周期将重复and/or 的一天或一周,一周的结束日可能小于一周的开始日。所以,我有:
- 生成了一个包含 100,000 个日期的列表(每行 1 个)
- 在您的 table
的 start/end 之间加入了那些日期
- 将每个连接的行转换为要计算的星期几
- left 连接到 1 到 7 的列表,并计算第 3 步的行数
注意:如果 end_date 是 "check out date",则可能需要从每条记录中扣除 1 天以进行补偿(下面没有这样做)。
可在 SQL Fiddle
此处查看此方法
MySQL 5.6 架构设置:
CREATE TABLE Table1
(`id` int, `start_date` datetime, `end_date` datetime)
;
INSERT INTO Table1
(`id`, `start_date`, `end_date`)
VALUES
(1, '2017-09-21 00:00:00', '2017-10-07 00:00:00'), ## added this row
(1, '2017-10-01 00:00:00', '2017-10-07 00:00:00'),
(2, '2017-10-04 00:00:00', '2017-10-07 00:00:00'),
(3, '2017-10-06 00:00:00', '2017-10-08 00:00:00')
;
查询:
set @commence := str_to_date('2000-01-01','%Y-%m-%d')
select
w.dy
, count(t.wdy)
from (
select 1 dy union all select 2 dy union all select 3 dy union all
select 4 dy union all select 5 dy union all select 6 dy union all select 7 dy
) w
left join (
select DAYOFWEEK(cal.dy) wdy
from (
select adddate( @commence ,t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) dy
from ( select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t0
cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t1
cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t2
cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t3
cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t4
) cal
INNER JOIN Table1 t on cal.dy between t.start_date and t.end_date
) t on w.dy = t.wdy
group by
w.dy
| dy | count(t.wdy) |
|----|--------------|
| 1 | 4 |
| 2 | 3 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 6 |
另请参阅:How to get list of dates between two dates in mysql select query 其中接受的答案是交叉联接集的基础,该交叉联接生成从指定日期开始的 100,000 个日期。然而,我修改了它的语法(显式交叉连接语法),一个参数作为起点,并使用 union all
提高效率。
我的预订 table 包含以下列:
id, start_date, end_date
我想知道在我的数据集中哪几天的预订最多。
我可以在开始日期上使用 dayofweek() 并以此为分组,并使用计数 (*)。但我还想包括预订开始和结束之间的天数。
示例输出为
dayofweek count(*)
1 1
2 1
3 1
4 2
5 3
6 3
7 1
下一组
id start_date end_date
1 2017-10-01 2017-10-07
2 2017-10-04 2017-10-07
3 2017-10-06 2017-10-08
您可以通过递归 table:
WITH cte AS
(
SELECT DATE_ADD(start_date INTERVAL 1 DAY) AS date, end_date, DAYOFWEEK(start_date) AS dw from bookings
UNION ALL
SELECT DATE_ADD(start_date INTERVAL 1 DAY), end_date, DAYOFWEEK(date)
FROM cte WHERE date <= end_date
)
SELECT COUNT(*), dw FROM cte GROUP BY dw
我假设您希望知道从开始到结束期间每个日期有多少房间已入住。这里的"trick" 是start/end 之间的长周期将重复and/or 的一天或一周,一周的结束日可能小于一周的开始日。所以,我有:
- 生成了一个包含 100,000 个日期的列表(每行 1 个)
- 在您的 table 的 start/end 之间加入了那些日期
- 将每个连接的行转换为要计算的星期几
- left 连接到 1 到 7 的列表,并计算第 3 步的行数
注意:如果 end_date 是 "check out date",则可能需要从每条记录中扣除 1 天以进行补偿(下面没有这样做)。
可在 SQL Fiddle
此处查看此方法MySQL 5.6 架构设置:
CREATE TABLE Table1
(`id` int, `start_date` datetime, `end_date` datetime)
;
INSERT INTO Table1
(`id`, `start_date`, `end_date`)
VALUES
(1, '2017-09-21 00:00:00', '2017-10-07 00:00:00'), ## added this row
(1, '2017-10-01 00:00:00', '2017-10-07 00:00:00'),
(2, '2017-10-04 00:00:00', '2017-10-07 00:00:00'),
(3, '2017-10-06 00:00:00', '2017-10-08 00:00:00')
;
查询:
set @commence := str_to_date('2000-01-01','%Y-%m-%d')
select
w.dy
, count(t.wdy)
from (
select 1 dy union all select 2 dy union all select 3 dy union all
select 4 dy union all select 5 dy union all select 6 dy union all select 7 dy
) w
left join (
select DAYOFWEEK(cal.dy) wdy
from (
select adddate( @commence ,t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) dy
from ( select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t0
cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t1
cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t2
cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t3
cross join (select 0 i union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t4
) cal
INNER JOIN Table1 t on cal.dy between t.start_date and t.end_date
) t on w.dy = t.wdy
group by
w.dy
| dy | count(t.wdy) |
|----|--------------|
| 1 | 4 |
| 2 | 3 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 6 |
另请参阅:How to get list of dates between two dates in mysql select query 其中接受的答案是交叉联接集的基础,该交叉联接生成从指定日期开始的 100,000 个日期。然而,我修改了它的语法(显式交叉连接语法),一个参数作为起点,并使用 union all
提高效率。