2011-01-10 18 views
5

partir de los datos por debajo de lo que necesito para seleccionar el registro más próximo a una fecha especificada para cada ID vinculado mediante SQL Server 2005:T-SQL - Selección por fecha cercana y agrupados por 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 

Por lo tanto la selección de ellos usando 01/10/2010 debe devolver:

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 

sé que esto debe ser posi ble, pero parece que no puedo entenderlo (debe ser demasiado cerca del final del día: P) ¡Si alguien puede ayudar o darme un empujón suave en la dirección correcta, sería muy apreciado!

EDIT: También he encontrado este SQL para obtener la fecha más cercana:

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

, pero no pudo encontrar la manera de incorporar en la consulta correctamente ...

Gracias

+0

Añadir ... agregó en la edición después de mi comentario. Ok, te escribiré la consulta completa. – Hogan

+0

Su título es engañoso, probablemente sea "seleccione el orden de ID en la fecha más cercana" – dvhh

+0

su ejemplo usando minutos ya que el primer parámetro para dateiff probablemente no funcione (ya que no tiene tiempo en sus fechas de ejemplo). Desea usar día - que puede ser abbr. como 'day',' dd', o 'd'. Curiosamente, toda la respuesta utiliza un abbr diferente. – Hogan

Respuesta

8

puede probar esto.

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 
; 

Usted no indique cómo quiere manejar el caso en varias filas en un grupo LinkedID representan el más cercano a la fecha prevista. Esta solución solo incluirá una fila Y, en este caso, no puede garantizar qué fila de los múltiples valores válidos está incluida.

Puede cambiar ROW_NUMBER() con RANK() en la consulta si desea incluir todas las filas que representan el valor más cercano.

+0

esto es mejor que mi consulta (solo una selección) pero la mía puede ser más clara para un principiante ... – Hogan

+0

Más información sobre ROW_NUMBER() está disponible aquí: http://msdn.microsoft.com/en-us/library/ms186734.aspx –

+0

@Hogan - No estoy seguro de estar de acuerdo. Si va a utilice un CTE de todos modos, entonces también podría aprovechar Row_Number(). – Thomas

4

Quiere ver el valor absoluto de la función DATEDIFF (http://msdn.microsoft.com/en-us/library/ms189794.aspx) por días.

La consulta puede ser algo como esto (no probado)

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í, ya lo he encontrado, pero olvidé mencionar eso en la pregunta, así que lo he actualizado. Gracias por mencionar que – w69rdy

+0

@ w69rdy: consulta de ejemplo agregada. – Hogan

+0

La consulta de ejemplo podría no ser correcta, debería ser mínima (días), de lo contrario, devolvería la mayor diferencia, ¿no? Además, no creo que el rendimiento en esto sea muy bueno en absoluto. En general, recomendaría usar la solución ROW_NUMBER(). Debería ser más directo y más eficiente. –

0

También puede tratar de hacerlo con una subconsulta en la instrucción de selección:

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, esto es def. menos rendimiento: una selección para cada enlace. – Hogan

+0

Sí, es solo para mesas pequeñas – pcofre

Cuestiones relacionadas