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]