2010-08-31 18 views
9

Tengo una tabla con muchos ID y muchas fechas asociadas con cada ID, e incluso algunos ID sin fecha. Para cada combinación de ID y fecha, deseo seleccionar la ID, la fecha y la siguiente fecha más grande también asociada con esa misma ID, o nula como la próxima fecha, si no existe ninguna.SQL - Seleccionar consulta de fecha siguiente

tabla muestra:

ID  Date 
1  5/1/10 
1  6/1/10 
1  7/1/10 
2  6/15/10 
3  8/15/10 
3  8/15/10 
4  4/1/10 
4  4/15/10 
4  

salida deseada:

ID  Date  Next_Date 
1  5/1/10  6/1/10 
1  6/1/10  7/1/10 
1  7/1/10  
2  6/15/10  
3  8/15/10  
3  8/15/10  
4  4/1/10  4/15/10 
4  4/15/10  
+0

cuál es su base de datos – Bharat

Respuesta

13
SELECT 
    mytable.id, 
    mytable.date, 
    (
     SELECT 
      MIN(mytablemin.date) 
     FROM mytable AS mytablemin 
     WHERE mytablemin.date > mytable.date 
      AND mytable.id = mytablemin.id 
    ) AS NextDate 
FROM mytable 

Esto ha sido probado en SQL Server 2008 R2 (pero que debería funcionar en otras bases de datos) y produce el siguiente resultado:

 
id   date     NextDate 
----------- ----------------------- ----------------------- 
1   2010-05-01 00:00:00.000 2010-06-01 00:00:00.000 
1   2010-06-01 00:00:00.000 2010-06-15 00:00:00.000 
1   2010-07-01 00:00:00.000 2010-08-15 00:00:00.000 
2   2010-06-15 00:00:00.000 2010-07-01 00:00:00.000 
3   2010-08-15 00:00:00.000 NULL 
3   2010-08-15 00:00:00.000 NULL 
4   2010-04-01 00:00:00.000 2010-04-15 00:00:00.000 
4   2010-04-15 00:00:00.000 2010-05-01 00:00:00.000 
4   NULL     NULL 

Actualización 1: Para aquellos que están interesados, he comparado el rendimiento de las dos variantes en SQL Server 2008 R2 (uno usa el agregado MIN y el otro utiliza TOP 1 con un ORDER BY):

Sin un índice en la columna de fecha, la versión MIN tenía un costo de 0.0187916 y la versión TOP/ORDER BY tenía un costo de 0.115073 por lo que la versión MIN era "mejor".

Con un índice en la columna de fecha, se realizaron de forma idéntica.

Tenga en cuenta que este estaba probando con sólo estos 9 registros por lo que los resultados podrían ser (muy) espuria ...

Actualización 2: Los resultados son válidos para 10.000 registros aleatorios uniformemente distribuidos. La consulta TOP/ORDER BY tarda tanto en ejecutarse en 100.000 registros que tuve que cancelarla y renunciar.

+0

es mejor usar el orden que las funciones agregadas. Tiene una gran mesa especialmente –

+0

@Andrii: No puedo hablar de otras DB, pero en SQL Server no debería hacer la diferencia. Si hay un índice, es lo suficientemente inteligente como para saber que puede leer la primera fila; si no hay índice, tiene que escanear toda la tabla de cualquier manera. De hecho, con un ORDER BY podría ser más lento ya que tendría que hacer una ordenación O (n * lg (n)) en lugar de un escaneo O (n). –

+0

Este es un db mssql con la consulta que se pasa a través de acceso, lo que significa que la consulta LIMIT no funcionaría de todos modos. La consulta mínima anterior funcionó perfectamente con la ligera adición de agregar mytable.id = mytablemin.id en la instrucción WHERE. La consulta es un poco lenta, pero no hay un índice en el campo de fecha que estoy usando en este momento. Gracias a todos por la ayuda. – John

1

SELECT id, date, (SELECT date FROM table t1 WHERE t1.date > t2.date ORDER BY t1.date LIMIT 1) FROM table t2

1

Si su base de datos es Oracle, puede utilizar las funciones lead() and lag().

SELECT id, date, 
LEAD(date, 1, 0) OVER (PARTITION BY ID ORDER BY Date DESC NULLS LAST) NEXT_DATE, 
FROM Your_table 
ORDER BY ID; 
+0

El código anterior produce un error para mí - el 0 debe ser nulo ya que Oracle sql se queja de que es un tipo de datos incompatible (número en lugar de fecha) el siguiente funciona bien: SELECT id, date, LEAD (date, 1, null) OVER (PARTICIÓN POR ID ORDER BY Fecha DESC NULLS LAST) NEXT_DATE, FROM Your_table – bawpie

Cuestiones relacionadas