2014-03-07 23 views
0

試想日這個名單範圍MySQL的 - 排除衝突的日期範圍

> SELECT * FROM range_table; 
+----+------------+------------+ 
| id | start  | end  | 
+----+------------+------------+ 
| 1 | 2014-01-01 | 2014-01-15 | /* -- Not conflicting */ 
| 2 | 2014-01-15 | 2014-01-16 | /* -- Conflicting  */ 
| 3 | 2014-01-15 | 2014-01-20 | /* |     */ 
| 4 | 2014-01-15 | 2014-01-19 | /*/    */ 
| 5 | 2014-01-24 | 2014-01-26 | /* -- Conflicting  */ 
| 6 | 2014-01-21 | 2014-01-25 | /*/    */ 
+----+------------+------------+ 

我試圖刪除衝突的範圍,只保留每個衝突組的第一次出現。

這是我應該在最後:

+----+------------+------------+ 
| id | start  | end  | 
+----+------------+------------+ 
| 1 | 2014-01-01 | 2014-01-15 | 
| 2 | 2014-01-15 | 2014-01-16 | 
| 5 | 2014-01-24 | 2014-01-26 | 
+----+------------+------------+ 

這裏是fiddle

+0

通過「第一次出現」你的意思是一個具有最早'id'? – Strawberry

回答

0

這裏是我的可能的解決方案:

SELECT `id`, `start`, `end` 
FROM (
    SELECT 
    r1.id 
    , r1.start 
    , r1.end 
    , COUNT(DISTINCT r2.id) AS "conflicts" 
    , MD5(GROUP_CONCAT(DISTINCT r2.id ORDER BY r2.id)) AS "group_chksum" 
    FROM range_table AS r1 
    LEFT JOIN range_table AS r2 
    ON (r1.end > r2.start AND r1.start < r2.end) 
    GROUP BY r1.id 
) AS tmp 
GROUP BY group_chksum 
; 

的想法是,把結果通過一系列的範圍和MySQL的容忍度的好處,以每個的第一個。

我敢肯定有更簡單的

+0

是的,這不是我會接受的! – Strawberry

+0

這是目前唯一真正回答我的問題的人。你很聰明,我相信它會幫助其他人。 –

+0

嗯,我仍然不明白你的數據集和你的結果集之間的關係。他們只是不匹配。 – Strawberry

1
SELECT x.* 
    FROM range_table x 
    LEFT 
    JOIN range_table y 
    ON y.start < x.end 
    AND y.end > x.start 
    AND y.id < x.id 
WHERE y.id IS NULL; 

http://sqlfiddle.com/#!2/6f723/26

查詢修改,以適應明顯修正簡短

+0

你的意思是'range_table'而不是'my_table'?而'y.start> = x.end'而不是'x.start

+0

是的......並且不......假設我的假設是正確的。請參閱編輯。 – Strawberry

+0

'WHERE y.id IS NULL'可以是有用的。不幸的是(例子更新)我並不總是有訂購的日期。 –