Как сделать это GROUP BY с желаемым результатом?

0

В принципе, у меня есть таблица со всеми остановками маршрута маршрута со значением time_from_start, что помогает привести их в порядок.

CREATE TABLE `api_routestop` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `route_id` int(11) NOT NULL,
  `station_id` varchar(10) NOT NULL,
  `time_from_start` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `api_routestop_4fe3422a` (`route_id`),
  KEY `api_routestop_15e3331d` (`station_id`)
)

Я хочу вернуть для каждой остановки строки время, чтобы перейти к следующей остановке.

Я пробовал с этим QUERY:

SELECT r1.station_id, r2.station_id, r1.route_id, COUNT(*), (r2.time_from_start - r1.time_from_start) as time
FROM api_routestop r1
LEFT JOIN api_routestop r2 ON r1.route_id = r2.route_id AND r1.id <> r2.id
GROUP BY r1.station_id
HAVING time >= 0
ORDER BY r1.route_id, r1.time_from_start, r2.time_from_start

Но группа по швам не работает, и результат выглядит следующим образом:

+------------+------------+----------+----------+------+
| station_id | station_id | route_id | COUNT(*) | time |
+------------+------------+----------+----------+------+
| Rub01      | Sal01      |        1 |       16 |    1 |
| Lyc02      | Sch02      |        2 |       17 |    2 |
| Paq01      | PoB01      |        3 |       15 |    1 |
| LaT02      | Gco02      |        4 |       16 |    1 |
| Sup01      | Tur01      |        5 |      132 |    1 |
| Oeu02      | CtC02      |        6 |       20 |    2 |
| Ver02      | Elo02      |        7 |       38 |    1 |
| Can01      | Mbo01      |        8 |       70 |    1 |
| Ver01      | Elo01      |        9 |       77 |    1 |
| MCH01      | for02      |       10 |       77 |    1 |
+------------+------------+----------+----------+------+

Если я это сделаю:

SELECT r1.station_id, r2.station_id, r1.route_id, COUNT(*), (r2.time_from_start - r1.time_from_start) as time
FROM api_routestop r1
LEFT JOIN api_routestop r2 ON r1.route_id = r2.route_id AND r1.id <> r2.id
GROUP BY r1.station_id, r2.station_id, r1.route_id
HAVING time >= 0
ORDER BY r1.route_id, r1.time_from_start, r2.time_from_start

Я соглашаюсь:

+------------+------------+----------+----------+------+
| station_id | station_id | route_id | COUNT(*) | time |
+------------+------------+----------+----------+------+
| Rub01      | Sal01      |        1 |        1 |    1 |
| Rub01      | ARM01      |        1 |        1 |    2 |
| Rub01      | MaV01      |        1 |        1 |    4 |
| Rub01      | COl01      |        1 |        1 |    5 |
| Rub01      | Str01      |        1 |        1 |    6 |
| Rub01      | Jau01      |        1 |        1 |    7 |
| Rub01      | Cdp01      |        1 |        1 |    9 |
| Rub01      | Rep01      |        1 |        1 |   11 |
| Rub01      | CoT01      |        1 |        1 |   12 |
| Rub01      | Ctr01      |        1 |        1 |   14 |
| Rub01      | FLy01      |        1 |        1 |   15 |
| Rub01      | Lib01      |        1 |        1 |   17 |
| Rub01      | Bru01      |        1 |        1 |   18 |
| Rub01      | Sch01      |        1 |        1 |   20 |
| Rub01      | Lyc01      |        1 |        1 |   22 |
| Rub01      | Res01      |        1 |        1 |   24 |
| Sal01      | ARM01      |        1 |        1 |    1 |
| Sal01      | MaV01      |        1 |        1 |    3 |
| Sal01      | COl01      |        1 |        1 |    4 |
| Sal01      | Str01      |        1 |        1 |    5 |
| Sal01      | Jau01      |        1 |        1 |    6 |
| Sal01      | Cdp01      |        1 |        1 |    8 |
| Sal01      | Rep01      |        1 |        1 |   10 |
| Sal01      | CoT01      |        1 |        1 |   11 |
| Sal01      | Ctr01      |        1 |        1 |   13 |
| Sal01      | FLy01      |        1 |        1 |   14 |
| Sal01      | Lib01      |        1 |        1 |   16 |
| Sal01      | Bru01      |        1 |        1 |   17 |
| Sal01      | Sch01      |        1 |        1 |   19 |
| Sal01      | Lyc01      |        1 |        1 |   21 |
...
3769 rows in set (0.07 sec)

Но что мне нужно сделать, чтобы иметь только первый результат для тех же r1.station_id и r1.route_id?

Теги:

3 ответа

2
Лучший ответ

Вы получаете много результатов назад, потому что вы получаете каждую остановку, соединенную с каждой другой остановкой на том же маршруте.

Таким образом, вам нужно будет идентифицировать остановку "Далее" в качестве остановки, которая имеет тот же идентификатор маршрута, но имеет минимальное время от начала позже текущего

Обновить Добавлен routeId для следующего запроса next_stop, чтобы иметь дело с случаем станций, используемых в нескольких маршрутах

SELECT
    r1.station_id, 
    r2.station_id, 
    r1.route_id, 
    r2.time_from_start - r1.time_from_start as time

FROM
api_routestop r1 
INNER JOIN (SELECT 
         r1.station_id , r2.route_id, min(r2.time_from_start) next_time_from_start
FROM 
  api_routestop r1
  LEFT JOIN api_routestop r2 ON r1.route_id = r2.route_id AND r1.id <> r2.id
       and r2.time_from_start > r1.time_from_start
  GROUP BY r1.Station_id, r2.route_id) next_stop

ON r1.Station_id = next_stop.station_id
   and r1.route_id = next_stop.route_id
LEFT JOIN api_routestop r2 
ON r2.time_from_start = r2.next_time_from_start
    and r1.route_id = r2.route_id
AND r2.time_from_start > r1.time_from_start
  • 0
    Хорошо, это близко, но у меня все еще есть некоторое отрицательное время и некоторый r2.station_id = r1.station_id
  • 0
    Я предположил, что time_from_start на маршруте было уникальным. Было ли это плохое предположение
Показать ещё 7 комментариев
2
SELECT station_id, coalesce( 
   (SELECT time_from_start 
      FROM api_routestop t2 
     WHERE t2.time_from_start > t1.time_from_start 
       AND t2.time_from_start <= (SELECT time_from_start FROM api_routestop t5 WHERE t5.station_id = '4' AND t5.route_id=t1.route_id)
       AND t2.route_id = t1.route_id 
     ORDER BY t2.time_from_start LIMIT 1), time_from_start) - time_from_start AS difference 
 FROM api_routestop t1 
WHERE t1.route_id = 1
  AND t1.time_from_start >= (SELECT time_from_start FROM api_routestop t4 WHERE t4.station_id = '2' AND t4.route_id=t1.route_id)
  AND t1.time_from_start <= (SELECT time_from_start FROM api_routestop t5 WHERE t5.station_id = '4' AND t5.route_id=t1.route_id)
ORDER BY time_from_start
  • 0
    +1 хорошее использование LIMIT 1, но, к сожалению, работает только на MYSQL
  • 0
    Я думаю, что на MSSQL это будет то же самое, но (ВЫБЕРИТЕ ТОП 1 time_from_start FROM (.....)). И LIMIT должен также быть удален.
Показать ещё 8 комментариев
1

Вы можете изменить схему? Если это просто добавление столбца, содержащего последовательное целое для всех остановок на маршруте, сделает этот запрос намного проще и эффективнее.

Невозможно это сделать.

SELECT
      station_id,
      route_id,
      time_from_start, 
      time_to_next
FROM
(
SELECT
    station_id,route_id,time_from_start,
    IF( @prev <> route_id, null, @time_from_start-time_from_start ) AS time_to_next,
    @time_from_start := time_from_start,
    @prev := route_id
  FROM api_routestop
  JOIN (SELECT @time_from_start := NULL, @prev := 0) AS r
  ORDER BY route_id, time_from_start DESC
  ) t
ORDER BY route_id,time_from_start
  • 0
    Это выглядит хорошо, но мне не удалось его выполнить.
  • 0
    @Natim - Я понимаю , что вы заменили yourtable с api_routestop ?
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню