2011-01-10 11 views
5

Z danych poniżej muszę wybrać rekord najbliższy określonym terminie za każdy Linked ID za pomocą SQL Server 2005:T-SQL - Selekcja według najbliższym terminie i pogrupowane według 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 

więc wybierając je za pomocą 01/10/2010 powinien zwrócić:

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 

wiem, że to musi być Possi ale wydaje mi się, że nie mogę tego obejść (musi być zbyt blisko końca dnia: P) Jeśli ktoś może mi pomóc lub delikatnie popchnąć we właściwym kierunku, byłoby to bardzo cenne!

EDIT: Również mam natknąć tej sql aby uzyskać możliwie najbliższe datę:

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

ale nie mógł dowiedzieć się, jak włączyć do prawidłowo zapytania ...

Dzięki

+0

Dodaj ... dodano w edycji po moim komentarzu. Ok, napiszę ci kompletne zapytanie. – Hogan

+0

Twój tytuł wprowadza w błąd, prawdopodobnie jest to "wybierz kolejność identyfikatorów według najbliższej daty" – dvhh

+0

Twój przykład za pomocą minut jako pierwszego parametru do datediff prawdopodobnie nie będzie działać (ponieważ nie masz czasu w przykładowych datach). Chcesz użyć dzień - który może być skrócony jako 'dzień',' dd' lub 'd'. Co ciekawe, wszystkie odpowiedzi używają innego abbr. – Hogan

Odpowiedz

8

można spróbować.

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 
; 

Nie wskazano, w jaki sposób obsługiwać przypadek, w którym wiele wierszy w grupie LinkedID reprezentuje najbliższą datę docelową. To rozwiązanie będzie zawierać tylko jeden wiersz. W tym przypadku nie można zagwarantować, który wiersz z wielu poprawnych wartości jest uwzględniony.

Możesz zmienić ROW_NUMBER() z RANK() w zapytaniu, jeśli chcesz uwzględnić wszystkie wiersze reprezentujące najbliższą wartość.

+0

to jest ładniejsze niż moje zapytanie (tylko jedno wybieranie), ale moje mogą być bardziej zrozumiałe dla początkujących ... – Hogan

+0

Więcej informacji na temat ROW_NUMBER() można znaleźć tutaj: http://msdn.microsoft.com/en-us/library/ms186734.aspx –

+0

@Hogan - Nie jestem pewien, czy się zgadzam. mimo to użyj CTE, wtedy równie dobrze możesz skorzystać z funkcji Row_Number(). – Thomas

4

Chcesz spojrzeć na bezwzględną wartość funkcji DATEDIFF (http://msdn.microsoft.com/en-us/library/ms189794.aspx) przez kilka dni.

Kwerenda może wyglądać mniej więcej tak (nie testowane)

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 tak, już się z tym zetknąłem, ale zapomniałem wspomnieć o tym w pytaniu, więc zaktualizowałem to. Dziękujemy za wzmiankę o dodaniu przykładowego zapytania – w69rdy

+0

@ w69rdy: – Hogan

+0

Przykładowe zapytanie może nie być prawidłowe - powinno być min (dni), w przeciwnym razie zwracałbyś największą różnicę, prawda? Ponadto, nie sądzę, że wyniki w tej sprawie będą bardzo dobre. Ogólnie zalecam użycie rozwiązania ROW_NUMBER(). Powinien być bardziej prosty i bardziej wydajny. –

0

Można też spróbować zrobić to z podzapytania w 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, to jest def. najmniej wydajne - wybierz dla każdego linkedid. – Hogan

+0

Tak, to tylko dla małych tabel – pcofre

Powiązane problemy