Рекурсивный / подмножественный запрос PostgreSQL

#postgresql

#postgresql

Вопрос:

У меня есть база данных результатов спортивных гонок, идентификатор гонки, который будет отображаться до 8 раз со строками для каждого имени спортсмена и данными о времени финиша.

Я пытаюсь извлечь 4-е время для каждой гонки.

Мой текущий (псевдо) код:

 races = "SELECT DISTINCT race_id, race_date FROM race_table ORDER BY race_date"

for race in races:
    fourth_place = "SELECT race_date, finish_time FROM race_table WHERE race_id={} ORDER BY finish_time LIMIT 1 OFFSET 3".format(race['race_id'])
 

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

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

Мои первоначальные попытки вернули только одну строку. Если это невозможно сделать в SQL SELECT, должен ли я изучать хранимые процедуры?

Редактировать: Пример набора данных, одна таблица, несортированный:

 race_id, race_date, athlete, finish_time
1001, 2021-01-16, "Joe B", 12.54
1001, 2021-01-16, "Emma J", 12.03
1001, 2021-01-16, "Tim N", 12.66
1001, 2021-01-16, "Joe B", 13.54
1001, 2021-01-16, "Sarah J", 12.28
1001, 2021-01-16, "Tom N", 13.22
1001, 2021-01-16, "Jim Z", 12.37
1001, 2021-01-16, "Emma K", 11.94
1002, 2021-01-22, "John B", 13.01
1002, 2021-01-22, "Jane D", 13.22
1002, 2021-01-22, "Ron H", 14.01
1002, 2021-01-22, "Dan M", 15.22
1002, 2021-01-22, "Gill P", 14.27
1002, 2021-01-22, "Jo V", 13.88
1002, 2021-01-22, "Harry T", 13.21
1002, 2021-01-22, "Jane Q", 14.62
 

Запрос должен возвращать одну строку за гонку (и это должно быть выбрано 4-м размещенным (4-м наименьшим числом) временем:

 race_date, finish_time
2021-01-16, 12.37
2021-01-22, 13.88
 

Комментарии:

1. where race_id in (1,2,3,) ?

2. Итак, вы хотите несколько гонок, и всегда четвертую в каждой? Здесь можно использовать обычные табличные выражения / оконные функции, вы можете упорядочить строки внутри рас и выбрать только ту, которую вы хотите

3. Схема таблицы, тестовые данные и ожидаемый результат ускорят ответ на ваш вопрос.

4. Я хотел бы, чтобы в каждой гонке была одна строка на гонку, и эта строка имеет 4-е самое быстрое время (СМЕЩЕНИЕ ПОРЯДКА 3). Я пойду и посмотрю на общие табличные выражения

Ответ №1:

Ваш пример:

 CREATE TABLE race_table(race_id integer, race_date date, athlete text, finish_time numeric (4,2));
INSERT INTO race_table VALUES
(1001, '2021-01-16', 'Joe B', '12.54'),
(1001, '2021-01-16', 'Emma J', '12.03'),
(1001, '2021-01-16', 'Tim N', '12.66'),
(1001, '2021-01-16', 'Joe B', '13.54'),
(1001, '2021-01-16', 'Sarah J', '12.03'),
(1001, '2021-01-16', 'Tom N', '13.22'),
(1001, '2021-01-16', 'Jim Z', '12.37'),
(1001, '2021-01-16', 'Emma K', '11.94'),
(1002, '2021-01-22', 'John B', '13.01'),
(1002, '2021-01-22', 'Jane D', '13.22'),
(1002, '2021-01-22', 'Ron H', '14.01'),
(1002, '2021-01-22', 'Dan M', '15.22'),
(1002, '2021-01-22', 'Gill P', '14.27'),
(1002, '2021-01-22', 'Jo V', '13.88'),
(1002, '2021-01-22', 'Harry T', '13.21'),
(1002, '2021-01-22', 'Jane Q', '14.62');
 

Я изменил ваши данные, чтобы они содержали повторяющееся значение для finish_time.

Вы начинаете с запроса, который добавляет столбец, содержащий ранг, к вашим данным:

 SELECT race_id,race_date,athlete,finish_time,
 rank() OVER(PARTITION BY race_id ORDER BY finish_time)AS row_nr
FROM race_table
 

Я думаю rank() , это то, что вам нужно. В зависимости от ваших требований вы можете использовать row_number() или dense_rank() вместо этого. Проверьте это — это влияет на то, как обрабатывается повторяющееся значение.

Затем используйте этот запрос и фильтруйте по row_nr :

 WITH race_ranked AS 
(SELECT race_id,race_date,athlete,finish_time,
 rank() OVER(PARTITION BY race_id ORDER BY finish_time)AS row_nr
FROM race_table )
SELECT race_id,race_date,athlete,finish_time 
FROM race_ranked 
WHERE row_nr = 4;
 

Вывод:

  race_id | race_date  | athlete | finish_time 
--------- ------------ --------- -------------
    1001 | 2021-01-16 | Jim Z   |       12.37
    1002 | 2021-01-22 | Jo V    |       13.88
 

Комментарии:

1. Спасибо. Результаты этого соответствуют моей рекурсии Python и более 5000 событий, время улучшается с 80 секунд до 3 секунд.