Максимальная отметка времени SQL Server в день для определенного столбца из объединенной таблицы

Я действительно новичок в SQL и, по сути, погуглил свой путь к этому моменту, сейчас я довольно застрял ... поэтому я надеюсь, что кто-то там может помочь!

Цель: получить строки с самой последней отметкой времени за день для каждого trip_id в MS SQL Server (есть несколько таблиц, которые необходимо соединить, чтобы получить необходимые данные).

Таким образом, каждый trip_id должен иметь 1 строку в день, вот так… [удалены некоторые столбцы для удобочитаемости]

timestamp,trip_id,stop_id,stop_code,arrival_time,departure_delay
4/28/2017 18:29,8888922,2847,52818,11:02:34,0
4/27/2017 18:26,8888922,2847,52818,11:02:34,60
4/25/2017 18:27,8888922,2847,52818,11:02:34,-120
4/28/2017 18:56,8888922,2847,52818,11:32:34,-60
4/25/2017 18:59,8888922,2847,52818,11:32:34,120
4/28/2017 19:34,8888922,2847,52818,12:02:34,360
4/27/2017 19:31,8888922,2847,52818,12:02:34,540
4/25/2017 19:27,8888922,2847,52818,12:02:34,-120

Однако прямо сейчас лучшее, что я смог сделать, это получить максимальную метку времени для каждого дня и offset_delay со следующим запросом

select
max(trip_updates.timestamp) as max, stop_times.trip_id, stops.stop_id, stops.stop_code, stop_times.arrival_time, trips.service_id,
stops.stop_name, stop_times.shape_dist_traveled, stop_time_updates.departure_delay
from stops
inner join stop_times on stops.stop_id = stop_times.stop_id
inner join trips on trips.trip_id = stop_times.trip_id
inner join routes on trips.route_id = routes.route_id
inner join trip_updates on stop_times.trip_id = trip_updates.trip_id
inner join stop_time_updates on trip_updates.oid = stop_time_updates.trip_update_id
where
stop_code = '52818'
and service_id = '1'
and stop_times.arrival_time between '11:00%' and '14:00%'
and route_short_name = '134'
group by stop_times.trip_id, stops.stop_id, stops.stop_code, stop_times.arrival_time, trips.service_id,
stops.stop_name, stop_times.shape_dist_traveled, stop_time_updates.departure_delay
order by stop_times.arrival_time asc, max(trip_updates.timestamp) desc

Что дает мне такие результаты, как...

timestamp,trip_id,stop_id,stop_code,arrival_time,departure_delay
4/28/2017 18:29,8888922,2847,52818,11:02:34,0
4/28/2017 18:21,8888922,2847,52818,11:02:34,30
4/28/2017 18:16,8888922,2847,52818,11:02:34,60
4/28/2017 18:11,8888922,2847,52818,11:02:34,120
4/27/2017 18:26,8888922,2847,52818,11:02:34,60
4/27/2017 18:22,8888922,2847,52818,11:02:34,30
4/27/2017 18:20,8888922,2847,52818,11:02:34,0

Любая помощь приветствуется! Благодарю вас!


person Brad T    schedule 01.05.2017    source источник
comment
Вам либо нужно выбрать меньше столбцов (чтобы вам не нужно было группировать по каждому отдельному столбцу), либо использовать метод ROW_NUMBER() (разделение по trip_id и упорядочение по временной метке desc).   -  person ZLK    schedule 02.05.2017
comment
Возможно, я делаю это неправильно, но теперь я просто получаю номер строки для каждой строки и каждой записи в день. select max(trip_updates.timestamp) as max, ROW_NUMBER() over(partition by max(trip_updates.timestamp) order by stop_times.trip_id) as row, stops.stop_id,...   -  person Brad T    schedule 02.05.2017


Ответы (2)


Как упоминалось в моем комментарии, одним из способов добиться этого, если вам нужно выбрать все текущие столбцы, будет использование ROW_NUMBER() оконной функции и удалив файл GROUP BY. Например,

SELECT [Max] = [timestamp], trip_id, stop_id, stop_code, arrival_time, service_id, stop_name, shape_dist_traveled, departure_delay
FROM
(
    SELECT trip_updates.[timestamp], stop_times.trip_id, stops.stop_id, stops.stop_code, stop_times.arrival_time, 
           trips.service_id, stops.stop_name, stop_times.shape_dist_traveled, stop_time_updates.departure_delay,
           RN = ROW_NUMBER() OVER (PARTITION BY stop_times.trip_id, CAST(trip_updates.[timestamp] AS DATE) ORDER BY trip_updates.[timestamp] DESC) 
           -- This assigns a row number for each row within each trip_id and each day, where a row number of 1 will be the highest timestamp.
    FROM ... 

    <put all your current joins / where clauses here>

    AND route_short_name = '134'
    -- Note: no GROUP BY
) AS T
WHERE RN = 1 -- This ensures you select only the the first row for each trip_id.
ORDER BY arrival_time, [timestamp]; 
person ZLK    schedule 02.05.2017
comment
Я понял, что в данных есть недостаток, который заставит меня вместо этого сравнивать поле метки времени (дата-время) с полем прибытия_время (varchar). Поле метки времени — это время UTC, а время прибытия — 07:00 UTC. Не могли бы вы помочь изменить это так, чтобы вместо максимальной временной метки она давала ближайшую временную метку к прибытия_время? - person Brad T; 07.05.2017
comment
Самое простое, что можно сделать, это, вероятно, изменить каждый раз, когда вы используете время прибытия, на DATEADD(HOUR, 7, arrival_time) или что-то в этом роде (-7 в столбце метки времени также будет работать, если вы хотите использовать местное время вместо времени UTC). - person ZLK; 08.05.2017

Вы можете присоединиться к подзапросу, который имеет то, что вы хотите:

SELECT  last_trip.timestamp AS max ,
        stop_times.trip_id ,
        stops.stop_id ,
        stops.stop_code ,
        stop_times.arrival_time ,
        trips.service_id ,
        stops.stop_name ,
        stop_times.shape_dist_traveled ,
        stop_time_updates.departure_delay
FROM    stops
        INNER JOIN stop_times ON stops.stop_id = stop_times.stop_id
        INNER JOIN trips ON trips.trip_id = stop_times.trip_id
        INNER JOIN routes ON trips.route_id = routes.route_id

        -- instead of joining directly to trip_updates, join to query
        -- that will number the entries per day
        INNER JOIN ( SELECT * ,
                            ROW_NUMBER() OVER ( PARTITION BY trip_id ORDER BY timestamp DESC ) AS rownum
                     FROM   trip_updates
                   ) AS last_trip ON stop_times.trip_id = last_trip.trip_id and rownum = 1 -- and join on the latest

        INNER JOIN stop_time_updates ON trip_updates.oid = stop_time_updates.trip_update_id
WHERE   stop_code = '52818'
        AND service_id = '1'
        AND stop_times.arrival_time BETWEEN '11:00%'
                                    AND     '14:00%'
        AND route_short_name = '134'
GROUP BY stop_times.trip_id ,
        stops.stop_id ,
        stops.stop_code ,
        stop_times.arrival_time ,
        trips.service_id ,
        stops.stop_name ,
        stop_times.shape_dist_traveled ,
        stop_time_updates.departure_delay
ORDER BY stop_times.arrival_time ASC ,
        MAX(trip_updates.timestamp) DESC;
person LordBaconPants    schedule 02.05.2017
comment
Похоже, это дает тот же результат, что и мой запрос, я получаю максимальную временную метку в день, но каждый вариант отправления_задержки имеет свою собственную строку вместо того, чтобы давать мне только последнюю временную метку для каждого дня для trip_id - person Brad T; 02.05.2017
comment
@BradT Ах, я пропустил and rownum = 1 при соединении подзапроса. Простите за это! - person LordBaconPants; 02.05.2017