SQL один запрос, чтобы выбрать макс / мин для выбранных идентификаторов (какой-то для каждого?) - PullRequest
3 голосов
/ 24 марта 2019

У меня есть простая структура sql:

CREATE TABLE main_tbl(
                id INTEGER PRIMARY KEY ASC,
                start_time TEXT NOT NULL,
                );

CREATE TABLE second_tbl (
                id     INTEGER PRIMARY KEY AUTOINCREMENT,
                data   BLOB,
                m_id   INTEGER NOT NULL,
                FOREIGN KEY(m_id) REFERENCES main_tbl(id) ON DELETE CASCADE
                );

CREATE INDEX m_id_idx ON second_tbl (m_id);
CREATE INDEX start_time_idx ON main_tbl (start_time);

И я хочу найти некоторые элементы из main_tbl:

SELECT id,start_time FROM main_tbl ORDER BY start_time DESC LIMIT X OFFSET Y;

, а затем для выбранного набораmain_tbl.id find min / max:

  SELECT data FROM second_tbl WHERE m_id=chosen_id AND SOME_CONDITION ORDER BY second_tbl.id ASC LIMIT 1
  UNION
  SELECT data FROM second_tbl WHERE m_id=chosen_id AND SOME_CONDITION ORDER BY second_tbl.id DESC LIMIT 1

На псевдоязыке это выглядит так:

foreach chosen_id IN (SELECT id,start_time FROM main_tbl ORDER BY start_time DESC LIMIT X OFFSET Y)
  SELECT data FROM second_tbl WHERE m_id=chosen_id AND SOME_CONDITION ORDER BY second_tbl.id ASC LIMIT 1
  UNION
  SELECT data FROM second_tbl WHERE m_id=chosen_id AND SOME_CONDITION ORDER BY second_tbl.id DESC LIMIT 1

Но как записать это в одном запросе SQL (на самом деле sqlite подмножество SQL)?

Если я напишу:

WITH chosen_ids(id,data) AS (SELECT id,start_time FROM main_tbl ORDER BY start_time DESC LIMIT X OFFSET Y)
  SELECT data FROM second_tbl WHERE m_id IN (SELECT id from chosen_ids) AND SOME_CONDITION ORDER BY second_tbl.id ASC LIMIT 1

, тогда я получу мининим для всех chosen_ids, а мне нужно для каждого из них.

Если я вместо этого использую JOINиз WITH Я могу установить только LIMIT/OFFSET для всего запроса JOIN, а не только для SELECT из main_tbl.

Обновление

Пример данных:

sqlite> SELECT id,start_time FROM main_tbl ORDER BY start_time DESC LIMIT 5 OFFSET 100;
900|2019-03-14T08:36:26.324937205+00:00
899|2019-03-14T06:36:26.324937205+00:00
898|2019-03-14T04:36:26.324937205+00:00
897|2019-03-14T02:36:26.324937205+00:00
896|2019-03-14T00:36:26.324937205+00:00

тогда я запустил подзапросы для 896-900, вот пример для 900:

sqlite> SELECT quote(data) FROM second_tbl WHERE m_id=900 AND data IS NOT NULL ORDER BY second_tbl.id ASC LIMIT 1;
X'000000008A128A5C00000000F5255E13000000000000F03F0000000000000040000000000000084000000000000010400000000000001440010000000000001840'


sqlite> SELECT quote(data) FROM second_tbl WHERE m_id=900 AND data IS NOT NULL ORDER BY second_tbl.id DESC LIMIT 1;
X'00000000AA2E8A5C00000000F544680D000000000000F03F0000000000000040000000000000084000000000000010400000000000001440010000000000001840'

1 Ответ

2 голосов
/ 24 марта 2019

Ну, вы можете написать это как один запрос, используя:

SELECT m.id, m.start_time, MIN(s.data) as min_data, MAX(s.data) as max_data
FROM main_tbl m LEFT JOIN
     second_tbl s
     ON s.m_id = m.id
GROUP BY m.id
ORDER BY start_time DESC
LIMIT X OFFSET Y;

РЕДАКТИРОВАТЬ:

Вы можете использовать коррелированные подзапросы:

SELECT m.id, m.start_time, 
       (SELECT s.data FROM second_tbl s WHERE m.m_id = s.chosen_id AND SOME_CONDITION ORDER BY s.id ASC LIMIT 1) as min_data,
       (SELECT s.data FROM second_tbl s WHERE m.m_id = s.chosen_id AND SOME_CONDITION ORDER BY s.id DESC LIMIT 1) as max_data
FROM main_tbl m 
ORDER BY start_time DESC
LIMIT X OFFSET Y;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...