T-SQL - ВЫБРАТЬ по ближайшей дате и сгруппировать по ID

Из приведенных ниже данных мне нужно выбрать запись, ближайшую к указанной дате, для каждого связанного идентификатора с использованием SQL Server 2005:

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

Поэтому выбор их с помощью 01/10/2010 должен вернуть:

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

Я знаю, что это должно быть возможно, но, похоже, я не могу обойти это вокруг (должно быть, слишком близко к концу дня:P) Если кто-то может помочь или слегка толкнуть меня в правильном направлении, это было бы очень признательно!

РЕДАКТИРОВАТЬ: Также я наткнулся на этот sql, чтобы получить ближайшую дату:

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

но не мог понять, как правильно включить в запрос...

Спасибо

3 ответа

Решение

Вы можете попробовать это.

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
;

Вы не указали, как вы хотите обработать случай, когда несколько строк в группе LinkedID представляют наиболее близкую к целевой дате. Это решение будет включать только одну строку И, в этом случае вы не можете гарантировать, какая строка из нескольких допустимых значений включена.

Вы можете изменить ROW_NUMBER() с помощью RANK() в запросе, если хотите включить все строки, представляющие ближайшее значение.

Вы хотите посмотреть на абсолютное значение функции DATEDIFF (http://msdn.microsoft.com/en-us/library/ms189794.aspx) по дням.

Запрос может выглядеть примерно так (не проверено)

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

Вы также можете попробовать сделать это с помощью подзапроса в операторе 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]
Другие вопросы по тегам