在一个表中查找重叠(日期/时间)行

时间:2009-03-27 11:49:52

标签: mysql

我有一张表,在每行中存储一个开始日期/时间和结束日期/时间的会议。

meetingID int
meetingStart datetime
meetingEnd datetime

期望的输出: 对于每对重叠的行,我想输出
meetingID,meetingStart,meetingID,meetingEnd

在MySQL中执行此类查询的最有效方法是什么?

4 个答案:

答案 0 :(得分:23)

SELECT  m1.meetingID, m1.meetingStart, m1.meetingEnd, m2.meetingID
FROM    t_meeting m1, t_meeting m2
WHERE   (m2.meetingStart BETWEEN m1.meetingStart AND m1.meetingEnd
        OR m2.meetingEnd BETWEEN m1.meetingStart AND m1.meetingEnd)
        AND m1.meetingID <> m2.meetingID

这将选择每对两次。

如果您希望只选择一对,请使用:

SELECT  m1.meetingID, m1.meetingStart, m1.meetingEnd, m2.meetingID
FROM    t_meeting m1, t_meeting m2
WHERE   (m2.meetingStart BETWEEN m1.meetingStart AND m1.meetingEnd
        OR m2.meetingEnd BETWEEN m1.meetingStart AND m1.meetingEnd)
        AND m2.meetingID > m1.meetingID

确保您在meetingStartmeetingEnd上拥有索引,以使查询有效运行。

但是,

MySQL可能会使用INDEX MERGE来运行此查询,这在当前实现中效率不高。

您也可以尝试使用:

SELECT  m1.*, m2.*
FROM    (
        SELECT  m1.meetingID AS mid1, m2.meetingID AS mid2
        FROM    t_meeting m1, t_meeting m2
        WHERE   m2.meetingStart BETWEEN m1.meetingStart AND m1.meetingEnd
                AND m2.meetingID <> m1.meetingID
        UNION
        SELECT  m1.meetingID, m2.meetingID
        FROM    t_meeting m1, t_meeting m2
        WHERE   m2.meetingEnd BETWEEN m1.meetingStart AND m1.meetingEnd
                AND m2.meetingID <> m1.meetingID
        ) mo, t_meeting m1, t_meeting m2
WHERE   m1.meetingID = mid1
        AND m2.meetingID = mid2

,这更复杂,但最有可能运行得更快。

答案 1 :(得分:1)

尝试使用此查询。 Quassnoi的解决方案被修改为忽略一个预订结束与另一个预订结束相同的情况。

SELECT  m1.meetingID_id, m1.meetingStart , m1.meetingEnd, m2.meetingID_id
FROM    bookings m1, bookings m2
WHERE   (m2.meetingStart BETWEEN m1.start AND DATE_SUB(m1.meetingEnd, INTERVAL 1 second)
        OR DATE_SUB(m2.meetingEnd, INTERVAL 1 second) BETWEEN m1.meetingStart AND m1.end)
        AND m1.meetingID_id > m2.meetingID_id

答案 2 :(得分:0)

可能是这样的:

SELECT m1.meetingID, m2.meetingID
FROM meeting AS m1, meeting AS m2
WHERE m1.meetingID < m2.meetingID
    AND m1.meetingStart BETWEEN m2.meetingStart AND m2.meetingEnd
    OR m1.meetingEnd BETWEEN m2.meetingStart AND m2.meetingEnd

仅选择m1.meetingID < m2.meetingID您不会将行与自身进行比较而不会重复,因为每行都会连接两次(m1,m2)和(m2,m1)

答案 3 :(得分:0)

将会议的开始和结束时间添加到结果行:

SELECT m1.meetingID AS firstID, m1.meetingStart AS firstStart, 
m1.meetingEnd AS firstEnd, m2.meetingID AS secondID, 
m2.meetingStart AS secondStart, m2.meetingEnd AS secondEnd 
FROM meeting AS m1, meeting AS m2 
WHERE (m2.meetingStart BETWEEN m1.meetingStart AND m1.meetingEnd) 
AND (m1.meetingID != m2.meetingID)

这种方式m2总是同时开始或在m1之后, 和m1.id!= m2.id确保它不包含与自身的匹配。

您不需要检查会议结束,作为重叠 可以通过比较会议开始来可靠地检测到。