2010-08-31 16 views
9

Ho una tabella con molti ID e molte date associate a ciascun ID e persino alcuni ID senza data. Per ogni combinazione di ID e data, desidero selezionare l'ID, la data e la data successiva più grande associata allo stesso ID o null come data successiva se non esiste nessuno.SQL: selezionare la query della data successiva

tabella di esempio:

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  

output desiderato:

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

il tuo database – Bharat

risposta

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 

Questo è stato testato su SQL Server 2008 R2 (ma dovrebbe funzionare su altri DBMS) e produce il seguente output:

 
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 

Update 1: Per coloro che sono interessato, ho confrontato le prestazioni delle due varianti in SQL Server 2008 R2 (uno utilizza l'aggregazione MIN e l'altro utilizza TOP 1 con un ORDER BY):

Senza un indice nella colonna della data, la versione MIN aveva un costo di 0,0187916 e la versione TOP/ORDER BY aveva un costo di 0,115073 quindi la versione MIN era "migliore".

Con un indice sulla colonna della data, si sono comportati in modo identico.

Si noti che questo stava testando con solo questi 9 record in modo che i risultati potrebbero essere (molto) spuria ...

Aggiornamento 2: I risultati valgono per 10.000 record casuali uniformemente distribuiti. La query TOP/ORDER BY impiega così tanto tempo per essere eseguita a 100.000 record e ho dovuto annullarla e rinunciare.

+0

è meglio utilizzare l'ordine rispetto alle funzioni aggregative. Si dispone di un grande tavolo in particolare –

+0

@Andrii: non posso parlare per altri DB ma su SQL Server non dovrebbe fare la differenza. Se c'è un indice è abbastanza intelligente da sapere che può solo leggere la prima riga; se non c'è indice, deve esaminare l'intera tabella in ogni caso. In effetti, con un ORDER BY potrebbe essere più lento poiché dovrebbe eseguire un ordinamento O (n * lg (n)) anziché una scansione O (n). –

+0

Questo è un mssql db con la query passata attraverso l'accesso, il che significa che la query LIMIT non funzionerebbe comunque. La query min sopra ha funzionato perfettamente con la leggera aggiunta dell'aggiunta di mytable.id = mytablemin.id nell'istruzione WHERE. La query è un po 'lenta, ma non c'è un indice sul campo della data che sto usando in questo momento. Grazie a tutti per l'aiuto. – 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

Se il db è Oracle, è possibile utilizzare lead() and lag() funzioni.

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

Il codice sopra riportato produce un errore per me - lo 0 dovrebbe essere nullo poichè sql Oracle si lamenta del fatto che si tratta di un tipo di dati incompatibile (numero invece di data) il sotto funziona bene però: ID SELECT, data, LEAD (data, 1, null) OVER (PARTITION BY ID ORDER BY Date DESC NULLS LAST) NEXT_DATE, FROM Your_table – bawpie

Problemi correlati