【问题标题】:SQL/Mysql query available dates and times in databaseSQL/Mysql 查询数据库中可用的日期和时间
【发布时间】:2016-11-25 00:33:50
【问题描述】:

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

场景:我有一个包含日期和时间的“日历”表(见下文),用户将设置他们的可用日期,通常是每天都有可用的时间段。所以我的表是这样的:

+------+------------+---------------------+---------------------+ 
| 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 年 9 月 3 日的 08:00:00 和 16:00:00 之间以及 2016 年 9 月 4 日的 08:00:00 和 16:00 之间可用: 00.
    • 在上面的示例中应该返回用户 1。

如果需要,我愿意就重新设计我的架构提出建议。

希望有人能帮我解决这个问题。

【问题讨论】:

    标签: mysql sql date laravel-5 calendar


    【解决方案1】:

    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 步:仅选择所有日期都有时间窗口的用户

    【讨论】:

    • 第一个案例它的工作,但不是第二个。如果我从 2016-09-01 08:00:00 到 2016-09-04 17:00:00 搜索,我会得到用户 1 的 3 个结果,但应该只得到 1。用户 1 仅在 2016-09-03 可用08:00:00 至 17:00:00。
    • 我只回答第一部分,第二部分需要大量的工作,这不是微不足道的。您需要将范围拆分为多个日期
    猜你喜欢
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多