2011-10-04 38 views
8

Tengo una tabla con columnas start_date y end_date. Lo que debemos hacer es seleccionar todo y agruparlos por conflictos de fechas para cada Object_ID.SQL Group By Date Conflicts

Un conflicto de fecha es cuando la fecha de inicio y/o finalización de una fila pasan por otras filas '. Por ejemplo, estos son algunos ejemplos de conflictos:

La fila 1 tiene fechas del 1 al 5, la fila 2 tiene fechas del 2 al 3.

La fila 1 tiene fechas del 2 al 5, la fila 2 tiene fechas del 1 al 3.

La fila 1 tiene fechas del 2 al 5, la fila 2 tiene fechas del 3 al 6.

La fila 1 tiene fechas del 2 al 5, la fila 2 tiene las fechas 1 ° a 7 °.

Así, por ejemplo, si tenemos algunos datos de la muestra (se supone que los números son sólo días del mes por simplicidad):

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

lo que esperaría a ver es la siguiente:

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

Y para un caso segunda prueba, he aquí algunos datos de muestra:

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 

Y para el segundo caso de prueba, lo que esperaríamos ver como salida:

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 

Sí, voy a necesitar alguna forma de diferenciar la primera y la segunda agrupación (la primera y última filas) pero no se han dado cuenta de que todo fuera. El objetivo es ver esta lista y luego, cuando hace clic en un grupo de conflictos, puede ver todos los conflictos en ese grupo.

Mi primer pensamiento fue intentar una cláusula GROUP BY CASE ... pero me envolví con la cabeza alrededor de sí misma.

El lenguaje que estoy usando para llamar a mysql es php. Entonces, si alguien conoce una solución de php-loop en lugar de una gran consulta de mysql, soy todo oídos.

Gracias de antemano.

Editar: Se agregó en las claves primarias para proporcionar un poco menos de confusión.

Editar: Agregado en un caso de prueba 2 para proporcionar un razonamiento más.

+0

no, object_id no se refiere a la id de la tabla, sólo se hace referencia a un objeto a una tabla diferente a un determinado código. Es decir, solo las filas con object_id's similares pueden tener la posibilidad de ser un conflicto. – Peanut

+0

Solo un pensamiento: si tiene la intención de hacer clic y expandir las filas del conflicto, poner '' en lugar de las fechas reales no parece tener mucho sentido. Si yo fuera usted, posiblemente usaría 'MIN (fecha_inicial) AS fecha_inicio' y' MÁX (fecha_fecha) AS fecha_del fin' para las filas del conflicto. De esta forma, el usuario podrá ver inmediatamente a qué rango de fechas pertenece el grupo de conflicto, sin tener que hacer clic/expandirlo primero. –

Respuesta

2

Esta consulta busca el número de duplicados:

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; 

Se puede utilizar esta consulta como la base de una consulta que le da exactamente lo que usted pidió (véase más adelante para la salida).

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; 

Tenga en cuenta que he utilizado una columna id distinguir las filas. Sin embargo, puede reemplazar la prueba de identificación no coincidente con las comparaciones en cada columna, es decir, reemplace od2.id != od1.id con pruebas de que ninguna otra columna es igual, pero que requeriría un índice único en todas las otras columnas para tener sentido y tener una identificación la columna es una buena idea de todos modos.

Aquí es una prueba con sus datos:

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); 

de salida de la primera consulta cuando se ejecuta en contra de esta muestra de datos:

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

de salida de la segunda consulta si se ejecuta en estos datos de muestra:

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

¿qué está haciendo exactamente tu cláusula group by? ¿De dónde vino el 1,2,3? – Peanut

+0

@Peanut 'group by 1,2,3' es una sintaxis abreviada para' group by column1, column2, column3' - en este caso 'group by od1.object_id, od1.start_date, od1.end_date'. Es parte del estándar SQL y funciona en todas las bases de datos. Me parece * mucho * más fácil de leer, y en mi humilde opinión * es * menos * propenso a errores, especialmente cuando las columnas que se agrupan son cálculos - muchos DB requieren que * repita * el cálculo en el grupo por, lo que lleva a una forma de duplicación y, por lo tanto, una fuente potencial de errores/errores – Bohemian

+0

Tu respuesta es llegar a lo que necesito, pero no del todo. Actualizaré el hilo ahora para explicar más. – Peanut

0

Oracle: Esto se puede hacer con una subconsulta en un grupo por instrucción CASE.

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

MySQL: Usted podría tener un punto de vista que tenía todos los conflictos.

seleccione distinct a1.appt, a2.appt de la cita a1, cita a2 donde a1.start < a2.end y a1.end> a2.start.

y simplemente haz un recuento (*) en esa tabla.

0

algo como lo siguiente debería funcionar:

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 

que podría estar fuera un poco, pero debería ayudarle a empezar.

Editar: sangría correctamente

+0

Solo hay 1 tabla, pero podría ver dónde derivar T2 diciendo unión interna (SELECCIONAR ....) como podría aplicarse T2. – Peanut