T-SQL: consulta de registros antes y después de la hora actual en la misma declaración

For you T-SQL gurus:

Tengo la siguiente tabla:

ID              Arrival
1       06:16:00
2       06:17:00
3               07:19:00
4       08:21:00
5       10:22:00
6       13:21:00
7       20:22:00

Say the time is currently 08:00 AM and I want to select 2 records before and after record with closest time to now. Result should return records with IDs 2,3,4,5 and 6.

Getting the records before and after record with ID=4 is straight forward but so far, I cannot figure out how to return the complete set as part of the same query. I have these two select statements:

SELECT TOP(2) * FROM Schedules 
where (datepart(hour, Arrival) - datepart(hour, getdate()))*60 + datepart(minute, Arrival) - datepart(minute, getdate())  < 0
order by (datepart(hour, Arrival) - datepart(hour, getdate()))*60 + datepart(minute, Arrival) - datepart(minute, getdate())

SELECT TOP(2) * FROM Schedules 
where (datepart(hour, Arrival) - datepart(hour, getdate()))*60 + datepart(minute, Arrival) - datepart(minute, getdate())  >= 0
order by (datepart(hour, Arrival) - datepart(hour, getdate()))*60 + datepart(minute, Arrival) - datepart(minute, getdate()) asc

which return records before and after. I tried using a union on both statements but this requires dropping the first order by clause which invalidates my query criteria.

Any ideas will help, thanks.

preguntado el 01 de febrero de 12 a las 22:02

2 Respuestas

Podemos utilizar ROW_NUMBER to partition on if the arrival is before or after and order by the absolute value of the difference between the arrival and the input time.

DECLARE @CurrentTime as  time 
SET @CurrentTime = '08:00 AM'

DECLARE @Schedules  table  (id int, arrival time)
INSERT INTO @Schedules
VALUES (1 , '06:16:00' ),
(2, '06:17:00' ),
(3, '07:19:00'),
(4, '08:21:00'),
(5, '10:22:00'),
(6, '13:21:00'),
(7, '20:22:00')

DECLARE @closestTime as time
SELECT TOP 1 @closestTime = arrival  FROM @Schedules ORDER BY ABS(DATEDIFF(mi, @CurrentTime ,arrival))

;WITH cte 
     AS (SELECT id, 
                arrival, 
                Row_number() OVER (PARTITION BY (CASE WHEN @closestTime > arrival THEN 1 
                                                      WHEN @closestTime < arrival THEN 2 END) 
                                   ORDER BY Abs(Datediff(mi, @closestTime, arrival))) rn 
         FROM   @Schedules) 
SELECT * 
FROM   cte 
WHERE  rn < 3 
        OR arrival = @closestTime 
ORDER  BY id

Resultados en

id          arrival          rn
----------- ---------------- --------------------
2           06:17:00.0000000 2
3           07:19:00.0000000 1
4           08:21:00.0000000 1
5           10:22:00.0000000 1
6           13:21:00.0000000 2

See working example at this data.se query

Respondido el 18 de enero de 21 a las 15:01

Wow, for this answer. Would never have figured this given time constraints. Thanks again and for the link. - Klaus Nji

Can you try the following? I have tested, got the result that u want

create table Arriavel (ID int, Arr_time time)

insert into Arriavel values (1, '06:16:00')
insert into Arriavel values (2, '06:17:00')
insert into Arriavel values (3, '07:19:00')
insert into Arriavel values (4, '08:21:00')
insert into Arriavel values (5, '10:22:00')
insert into Arriavel values (6, '13:21:00')
insert into Arriavel values (7, '20:22:00')


declare @cur_time time

set @cur_time = '08:00:00'

select max(arr_time) arr_time
from Arriavel
where arr_time < @cur_time

union all

select min(arr_time) arr_time
from Arriavel
where arr_time > @cur_time

Respondido 02 Feb 12, 03:02

"Result should return records with IDs 2,3,4,5 and 6" your SQL only returns the times for 3 and 4 - Conrad Frix

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.