2017-10-06 150 views
0

我有以下的列的预订表:MySQL的算两个日期之间的星期在一个表

编号,日期,结束日期

我想知道哪些日子已经过了最预订我的数据集。

我可以在开始日期使用dayofweek(),也可以使用这个数字并使用count(*)。但我也想包括从预订开始到结束之间的日子。

一个例子输出wouldbe

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 
+0

使用日历表(包含您需要的所有日期)并使用BETWEEN条件将其加入到表中。 –

+0

不幸的是,10月份是在星期天开始的。 – Strawberry

回答

0

我假设你想知道的东西比如在开始和结束之间的每个日期有多少个房间被填满。这里的“诀窍”是,从开始/结束之间的很长一段时间将重复一天或一周,并且/或者一周的结束日可能小于一周的开始日。所以,我有:

  1. 产生100000个日期(1每行)的列表
  2. 加入你的表的开始/结束
  3. 转换的各参加行的周数日之间的日期算
  4. 左接合到清单1至7,并计数步骤中的行3

注意:如果END_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 

Results

| 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那里接受的答案是一组交叉的基础上加入产生从提名日起10万周的日期。然而,我修改了语法(显式交叉连接语法),一个参数作为起点,并使用union all来提高效率。

+0

这个工程!然而,我有一个100行的测试表,目前需要20秒,如果说我拥有100,000个,这个查询运行得如何? –

+0

a。我无法真正预测到,而且b。它很可能取决于你的索引,并且c。代替动态生成的日期列表,您可以改为创建一个表并将其也编入索引。请始终参考性能详情的解释计划。如果问一个关于性能的新问题,包括表和相关索引的完整DDL。加解释计划输出(如文本) –

0

您可以用递归表实现这一点:

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 
+1

附加说明:递归表可能不可用,具体取决于所使用的版本(即MariaDB <10.2不可能) –

+0

使用MySQL 5。7 –

相关问题