2011-01-10 1 views
5

Dai dati di seguito ho bisogno di selezionare il record più vicino ad una data determinata per ciascun ID collegato tramite SQL Server 2005:T-SQL - SELEZIONA per data più vicina e raggruppate per ID

ID  Date  Linked ID 
........................... 
1 2010-09-02  25 
2 2010-09-01  25 
3 2010-09-08  39 
4 2010-09-09  39 
5 2010-09-10  39 
6 2010-09-10  34 
7 2010-09-29  34 
8 2010-10-01  37 
9 2010-10-02  36 
10 2010-10-03  36 

Quindi, selezionandoli con 01/10/2010 dovrebbe restituire:

1 2010-09-02  25 
5 2010-09-10  39 
7 2010-09-29  34 
8 2010-10-01  37 
9 2010-10-02  36 

so che questo deve essere possi ble, ma non riesco a girarmi intorno (dev'essere troppo vicino alla fine della giornata: P) Se qualcuno può aiutarmi o darmi una spinta gentile nella giusta direzione, sarebbe molto apprezzato!

EDIT: Inoltre mi sono imbattuto in questo sql per ottenere la data più vicina:

abs(DATEDIFF(minute, Date_Column, '2010/10/01')) 

ma non riusciva a capire come incorporare nella query correttamente ...

Grazie

+0

Aggiungi ... si è aggiunto in fase di montaggio, dopo il mio commento. Ok ti scriverò la query completa. – Hogan

+0

Il tuo titolo è fuorviante, probabilmente è "seleziona ordine ID secondo la data più vicina" – dvhh

+0

il tuo esempio usando minuti poiché il primo parametro di datediff probabilmente non funzionerà (dato che non hai tempo nelle date di esempio.) Vuoi usare giorno - che può essere abbr. come 'day',' dd' o 'd'. È interessante notare che tutta la risposta usa un abbr diverso. – Hogan

risposta

8

si può provare questo.

DECLARE @Date DATE = '10/01/2010'; 

WITH cte AS 
    (
    SELECT ID, LinkedID, ABS(DATEDIFF(DD, @date, DATE)) diff, 
     ROW_NUMBER() OVER (PARTITION BY LinkedID ORDER BY ABS(DATEDIFF(DD, @date, DATE))) AS SEQUENCE 
    FROM MyTable 
    ) 

SELECT * 
FROM cte 
WHERE SEQUENCE = 1 
ORDER BY ID 
; 

Non hai indicare come si desidera gestire il caso in cui più righe in un gruppo LinkedID rappresentano la più vicina alla data di destinazione. Questa soluzione includerà solo una riga e, in questo caso, non è possibile garantire quale riga di più valori validi sia inclusa.

È possibile modificare ROW_NUMBER() con RANK() nella query se si desidera includere tutte le righe che rappresentano il valore più vicino.

+0

questo è più bello della mia query (solo una selezione) ma la mia può essere più chiara per un principiante ... – Hogan

+0

Ulteriori informazioni su ROW_NUMBER() sono disponibili qui: http://msdn.microsoft.com/en-us/library/ms186734.aspx –

+0

@Hogan - Non sono sicuro di essere d'accordo. utilizzare comunque un CTE, quindi si potrebbe anche trarre vantaggio da Row_Number(). – Thomas

4

Si desidera esaminare il valore assoluto della funzione DATEDIFF (http://msdn.microsoft.com/en-us/library/ms189794.aspx) per giorni.

la query può essere simile a questa (non testato)

with absDates as 
(
    select *, abs(DATEDIFF(day, Date_Column, '2010/10/01')) as days 
    from table 
), mdays as 
( 
    select min(days) as mdays, linkedid 
    from absDates 
    group by linkedid 
) 
select * 
from absdates 
inner join mdays on absdays.linkedid = mdays.linkedid and absdays.days = mdays.mdays 
+0

@Hogan Ah sì, ho già incontrato, ma ho dimenticato di menzionare che nella domanda, quindi l'ho aggiornato. Grazie per aver menzionato che – w69rdy

+0

@ w69rdy: query di esempio aggiunta. – Hogan

+0

La query di esempio potrebbe non essere corretta, dovrebbe essere min (giorni), altrimenti si restituirebbe la differenza maggiore, giusto? Inoltre, non penso che la performance su questo sarà molto buona a tutti. In generale, consiglierei di utilizzare la soluzione ROW_NUMBER(). Dovrebbe essere più semplice e più performante. –

0

Si può anche provare a farlo con una subquery nell'istruzione SELECT:

select [LinkedId], 
     (select top 1 [Date] from [Table] where [LinkedId]=x.[LinkedId] order by abs(DATEDIFF(DAY,[Date],@date))) 
from [Table] X 
group by [LinkedId] 
+0

Wow, questo è def. meno performante - una selezione per ogni linkedid. – Hogan

+0

Sì, è solo per piccoli tavoli – pcofre