SQL / Mysql查询数据库中的可用日期和时间

时间:2016-11-25 00:33:51

标签: mysql sql date laravel-5 calendar

我需要一些帮助来查询我的日历/日期表

场景:我有一个"日历"如果日期和时间表(见下文),用户将设置他们的可用日期,通常是每天可用的时间段。所以我的表看起来像这样:

+------+------------+---------------------+---------------------+ 
| ID   | user_id    | start_date          | end_date            | 
+------+------------+---------------------+---------------------+ 
|    1 |          1 | 2016-09-01 08:00:00 | 2016-09-01 16:00:00 | 
|    2 |          1 | 2016-09-03 00:00:00 | 2016-09-03 23:59:59 | 
|    3 |          1 | 2016-09-04 00:00:00 | 2016-09-04 16:00:00 | 
|    4 |          1 | 2016-09-05 08:00:00 | 2016-09-05 16:00:00 | 
|    5 |          2 | 2016-09-05 08:00:00 | 2016-09-05 16:00:00 | 
|    6 |          2 | 2016-09-07 08:00:00 | 2016-09-07 16:00:00 | 
|    7 |          2 | 2016-09-08 08:00:00 | 2016-09-08 16:00:00 | 
|    8 |          2 | 2016-09-08 18:00:00 | 2016-09-08 22:00:00 |
+------+------------+---------------------+---------------------+ 

我们这里有2个用户,所以我想要以下内容:

  • 如果我搜索start_date = 2016-09-05 08:00:00和end_date = 2016-09-05 16:00:00它应该返回用户1和2.因为它们都有一个条目与这些日期。同样如果start_date = 2016-09-05 09:00:00和end_date = 2016-09-05 15:00:00,这也应该返回两个用户,因为我搜索的时间是在时间段之间示例中显示。

  • 第二种情况有点棘手,如果用户搜索start_date = 2016-09-03 08:00:00和end_date = 2016-09-04 16:00:00我希望查询检查以下内容:

    • 在这些时间查看用户是否每天都可用。
    • 所以在这种情况下,用户可以在2016-09-03 08:00:00到16:00:00之间以及2016-09-04 08:00:00到16:00之间使用: 00。
    • 在此示例中应该返回用户1.

我可以根据需要重新设计我的架构。

希望有些人可以帮助我。

1 个答案:

答案 0 :(得分:0)

DEMO 包含一些附加代码注释,并显示查询的演变方式。另外,我为user_id = 2添加了另一行,以显示如何仅匹配范围内两天中的一天。

SELECT U.`user_id`
FROM (
        select a.selectDate,
               CONCAT(a.selectDate, ' ', time(@s_date)) as start_time,
               CONCAT(a.selectDate, ' ', time(@s_date)) as end_time
        from (
            select '1900-01-01' + INTERVAL (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) + (10000 * e.a)) DAY as selectDate
            from       (select 0 as a 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) as a
            cross join (select 0 as a 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) as b
            cross join (select 0 as a 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) as c
            cross join (select 0 as a 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) as d
            cross join (select 0 as a 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) as e
        ) a
        CROSS JOIN (SELECT @s_date := '2016-09-03 08:00:00', @e_date := '2016-09-04 16:00:00') par
        -- CROSS JOIN (SELECT @s_date := '2016-09-05 08:00:00', @e_date := '2016-09-05 16:00:00') par
        -- CROSS JOIN (SELECT @s_date := '2016-09-05 09:00:00', @e_date := '2016-09-05 15:00:00') par
        WHERE selectDate BETWEEN date(@s_date) 
                             AND date(@e_date)
     ) D
CROSS JOIN (SELECT DISTINCT `user_id` FROM Table1) U
LEFT  JOIN Table1 T
        ON U.`user_id` = T.`user_id`
       AND D.start_time <= T.`end_date`
       AND D.end_time   >= T.`start_date`
GROUP BY U.`user_id`
HAVING COUNT(U.`user_id`) = COUNT(T.`user_id`);

<强>输出

  • 第1步:创建日期列表,在本例中为273年
  • 步骤2:选择参数中定义范围之间的所有日期,还包括每个日期的时间窗口。
  • 步骤3:全部加入以查看该时间窗口中用户的日期
  • 步骤4:仅选择具有所有日期的时间窗口的用户

enter image description here