2014-03-07 20 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'可以是有用的。不幸的是(例子更新)我并不总是有订购的日期。 –