2011-01-10 2 views
5

Из данных ниже нужно выбрать запись ближайших к указанной дате для каждого Linked ID с помощью 2005 SQL Server:T-SQL - ВЫБРАТЬ на ближайшую дату и сгруппированных BY 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 

Поэтому, выбирая их с помощью 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 

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

EDIT: Также я пришел через эту SQL, чтобы получить наиболее близкую дату:

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

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

Благодаря

+0

Добавить ... Вы добавили в редактировании после моего комментария. Хорошо, я напишу вам полный запрос. – Hogan

+0

Ваш заголовок вводит в заблуждение, вероятно, «выберите ID-заказ на ближайшую дату» – dvhh

+0

ваш пример, используя минус, поскольку первый параметр для датиффа, вероятно, не будет работать (поскольку у вас нет времени в датах вашего примера.) Вы хотите использовать день - который может быть абб. как 'day',' dd' или 'd'. Интересно, что весь ответ использует другой абб. – Hogan

ответ

8

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

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() в запросе, если хотите включить все строки, представляющие ближайшее значение.

+0

это лучше, чем мой запрос (только один выбор), но мой может быть яснее начинающему ... – Hogan

+0

Дополнительная информация о ROW_NUMBER() доступна здесь: http://msdn.microsoft.com/en-us/library/ms186734.aspx –

+0

@ Хоган - Я не уверен, что согласен. Если вы собираетесь используйте CTE в любом случае, тогда вы также можете воспользоваться преимуществами Row_Number(). – Thomas

4

Вы хотите посмотреть абсолютное значение функции 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 
+0

@ Хоган. Ах, я уже наткнулся на это, но забыл упомянуть, что в вопросе, поэтому я обновил его. Спасибо, что упомянул, что – w69rdy

+0

@ w69rdy: добавлен пример запроса. – Hogan

+0

Пример запроса может быть неправильным - он должен быть min (дни), иначе вы бы вернули наибольшую разницу, не так ли? Кроме того, я не думаю, что производительность на этом будет очень хорошей. В общем, я бы рекомендовал использовать решение ROW_NUMBER(). Он должен быть более простым и более эффективным. –

0

Вы также можете попробовать сделать это с помощью подзапроса в операторе выбора:

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

Вау, это def. наименее эффективный - выбор для каждого связанного. – Hogan

+0

Да, это просто для маленьких столов – pcofre