在议程中找到第一个免费日期

时间:2012-06-14 19:27:14

标签: php mysql php-5.3

在我的组件中,我创建了一个议程,用户可以在其中保存约会 议程表非常简单:有标题,描述和开始/结束日期时间字段。

当用户添加新活动时,我希望用第一个空白点暗示他。

我怎样才能做到这一点?
这可能是单个/一堆查询,或者我必须创建一个循环,直到找到第一个空白点?

例如,这是我的表:

|  ID |       Start date     |       End date      |
|  1  | 2012-06-14 09:00:00  | 2012-06-14 09:32:00 |
|  2  | 2012-06-14 15:00:00  | 2012-06-14 15:45:00 |
|  3  | 2012-06-14 18:20:00  | 2012-06-14 18:55:00 |

第一个免费日期时间应为2012-06-14 09:33:00,我该如何获取此日期?

1 个答案:

答案 0 :(得分:2)

有趣的挑战要在一个查询中完成:)我花了一段时间,但我带来了解决方案。有了这些假设:

  • 最短约会时间为30分钟
  • 约会开始和结束一天
  • 天从9:00开始,到17:00结束
  • 结束时间和开始时间之间的最小间隔为1分钟

有4个案例需要考虑:

  1. 早上有空闲时间
  2. 白天有空闲时间
  3. 第一个空闲时段是db
  4. 中最后一次约会的第二天
  5. 从现在开始,你有所有免费插槽
  6. 所以你必须选择这些日期的最低格式。

    查询:

    SELECT
        MIN(next_start_date) AS next_start_date
    FROM
    ( 
        (
            SELECT 
                DATE_FORMAT(t1.start_date,'%Y-%m-%d 09:00:00') AS next_start_date
            FROM
                agenda t1
            WHERE
                t1.start_date > NOW()
            AND
                TIME(t1.start_date) > '09:30:00'
            AND
                NOT EXISTS(
                    SELECT 1 FROM agenda t2 WHERE DATE(t2.start_date) = DATE(t1.start_date) AND TIME(t2.start_date) <= '09:30:00'
                )
            LIMIT 1
        )
        UNION
        (
            SELECT
                t3.end_date + INTERVAL 1 MINUTE AS next_start_date
            FROM
                agenda t3
            WHERE
                t3.start_date > NOW()
            AND
                TIME(t3.start_date) >= '09:00:00'
            AND
                TIME(t3.end_date) < '16:30:00'
            AND NOT EXISTS
                (SELECT 1 FROM agenda t4 WHERE TIMESTAMPDIFF(MINUTE,t3.end_date,t4.start_date) BETWEEN 0 AND 30 )
            ORDER BY
                t3.start_date ASC
            LIMIT 1
        )
        UNION
        (
            SELECT CONCAT(CAST(DATE((SELECT MAX(t5.start_date) + INTERVAL 1 DAY FROM agenda t5 WHERE t5.start_date > NOW())) AS CHAR), ' 09:00:00') AS next_start_date
        )
        UNION
        (
            SELECT 
                IF( 
                    TIME(NOW()) < '09:00:00', 
                    DATE_FORMAT(NOW(),'%Y-%m-%d 09:00:00'), 
                    IF(
                        TIME(NOW()) < '16:30', 
                        NOW(),
                        DATE_FORMAT(NOW() + INTERVAL 1 DAY,'%Y-%m-%d 09:00:00' ) 
                    )
                ) AS next_start_date
            FROM
                (SELECT 1) t6
            WHERE NOT EXISTS(
                SELECT 1 FROM agenda t7 WHERE t7.start_date > NOW()
            )
            LIMIT 1
        )
    ) t
    

    当然它并不完美 - 当第二天出现下一个免费插槽时,有可能是星期六或其他一天下班。考虑到这一点,最好的方法是检查返回是否为有效工作日,如果不是,则重复查询,NOW()替换为下一个有效工作日的日期字符串。