2011-10-04 83 views
8

我有一个表的列start_date和end_date。我们需要做的是选择所有东西并按照每个Object_ID的日期冲突对它们进行分组。SQL Group按日期冲突

日期冲突是指行的开始日期和/或结束日期通过另一行时。例如,下面是一些冲突示例:

第1行的日期为第1至第5行,第2行的日期为第2至第3。

第1行的日期是第2个到第5个,第2行的日期是第1个到第3个。

第1排第2至第5排,第2排排第3至第6排。

第1行的日期是第2个到第5个,第2行的日期是第1个到第7个。

因此,举例来说,如果我们有一些样本数据(假设数字是一个月简单的几天):

id | object_id | start_date | end_date 
1 | 1   | 1   | 5 
2 | 1   | 2   | 4 
3 | 1   | 6   | 8 
4 | 2   | 2   | 3 

什么,我希望看到的是:

object_id | start_date | end_date | numconflicts 
1   | <na>  | <na>  | 2 
1   | 6   | 8  | 0 or null 
2   | 2   | 3  | 0 or null 

而对于第二个测试案例,下面是一些示例数据:

id | object_id | start_date | end_date 
1 | 1   | 1   | 5 
2 | 1   | 2   | 4 
3 | 1   | 6   | 8 
4 | 2   | 2   | 3 
5 | 2   | 4   | 5 
6 | 1   | 2   | 3 
7 | 1   | 10   | 12 
8 | 1   | 11   | 13 

而对于第二个测试案例,我希望看到作为输出:

object_id | start_date | end_date | numconflicts 
1   | <na>  | <na>  | 3 
1   | 6   | 8  | 0 or null 
2   | 2   | 3  | 0 or null 
2   | 4   | 5  | 0 or null 
1   | <na>  | <na>  | 2 

是的,我需要区分第一和第二组(第一个和最后一个行)的一些方式,但我还没有完全想通了这一点。目标是查看此列表,然后当您单击一组冲突时,您可以查看该组中的所有冲突。

我的第一个想法是尝试一些GROUP BY CASE ...子句,但我只是用头围绕自己。

我用来调用mysql的语言是php。所以如果有人知道一个PHP循环的解决方案,而不是一个大型的MySQL查询我都耳闻。

在此先感谢。

编辑:在主键中添加,以减少混淆。

编辑:添加在测试用例2中以提供更多推理。

+0

没有,OBJECT_ID并不是指表的ID,它只是指对象到不同的表使用该ID。意思是,只有具有类似object_id的行可能有冲突的可能性。 – Peanut

+0

只是一个想法:如果你打算冲突行是可点击和可扩展的,把''而不是实际日期似乎没有太大意义。如果我是你,我可能会使用'MIN(start_date)AS start_date'和'MAX(end_date)AS end_date'作为冲突行。这样用户就能立即看到冲突组属于哪个日期范围,而不必先点击/展开它。 –

回答

2

此查询查找重复的次数:

select od1.object_id, od1.start_date, od1.end_date, sum(od2.id is not null) as dups 
from object_date od1 
left join object_date od2 
    on od2.object_id = od1.object_id 
    and od2.end_date >= od1.start_date 
    and od2.start_date <= od1.end_date 
    and od2.id != od1.id 
group by 1,2,3; 

您可以使用此查询的查询,让你你问什么了(见下面的输出)的基础。

select 
    object_id, 
    case dups when 0 then start_date else '<na>' end as start_date, 
    case dups when 0 then end_date else '<na>' end as end_date, 
    sum(dups) as dups 
from (
    select od1.object_id, od1.start_date, od1.end_date, sum(od2.id is not null) as dups 
    from object_date od1 
    left join object_date od2 
    on od2.object_id = od1.object_id 
    and od2.end_date >= od1.start_date 
    and od2.start_date <= od1.end_date 
    and od2.id != od1.id 
    group by 1,2,3) x 
group by 1,2,3; 

注意,我已经使用了id柱来区分的行。但是,您可以用每个列替换id不匹配的测试,即将od2.id != od1.id替换为其他列不相同的测试,但这需要所有其他列上的唯一索引才有意义,并且具有id无论如何,列是一个好主意。

:当针对该样本数据运行

+-----------+------------+----------+------+ 
| object_id | start_date | end_date | dups | 
+-----------+------------+----------+------+ 
|   1 |   1 |  5 | 1 | 
|   1 |   2 |  4 | 1 | 
|   1 |   6 |  8 | 0 | 
|   2 |   2 |  3 | 0 | 
+-----------+------------+----------+------+ 

输出第二查询:当针对该样本数据运行第一查询的

create table object_date (
    id int primary key auto_increment, 
    object_id int, 
    start_date int, 
    end_date int 
); 
insert into object_date (object_id, start_date, end_date) 
    values (1,1,5),(1,2,4),(1,6,8),(2,2,3); 

输出:

下面是使用你的数据测试

+-----------+------------+----------+------+ 
| object_id | start_date | end_date | dups | 
+-----------+------------+----------+------+ 
|   1 | 6   | 8  | 0 | 
|   1 | <na>  | <na>  | 2 | 
|   2 | 2   | 3  | 0 | 
+-----------+------------+----------+------+ 
+0

你的group by子句究竟做了什么? 1,2,3是从哪里来的? – Peanut

+0

@Pananut'group by 1,2,3'是'group by column1,column2,column3'的缩写语法 - 在这种情况下是'group by od1.object_id,od1.start_date,od1.end_date'。它是SQL标准的一部分,适用于每个数据库。我发现它很容易阅读,而且恕我直言它很少容易出错,尤其是当列被分组时,计算 - 很多数据库要求你重复组中的计算,这导致了重复的形式,因此是潜在的错误/错误来源 – Bohemian

+0

您的回答正在达到我所需要的,但并不完全在那里。我现在更新线程来解释更多。 – Peanut

0

Oracle:这可以通过CASE语句的组中的子查询来完成。

https://forums.oracle.com/forums/thread.jspa?threadID=2131172

MySQL的:你可以有一个图,该把所有的冲突。

select a1.appt,a2.appt from appointment a1,appointment a2 where a1.start < a2.end and a1.end> a2.start。

然后只需在该表上进行计数(*)。

0

类似下面应该工作:

select T1.object_id, T1.start_date, T1.end_date, count(T1.object_id) as numconflicts 
from T1 
inner join T2 on T1.start_date between T2.start_date and T2.end_date 
inner join T3 on T1.end_date between T2.start_date and T2.end_date 
group by T1.object_id 

我可能会关闭一点点,但它应该帮助您开始。

编辑:缩进得当

+0

只有1个表格,但我可能会看到T2的说法可能适用于T2的内部联接(SELECT ....)。 – Peanut