Как получить только ограниченное количество объединенных результатов? - PullRequest
0 голосов
/ 08 мая 2018

Предположим, у меня есть следующие таблицы:

Проекты

  • id INT
  • имя VARCHAR
  • owner_id INT

версия

  • id INT
  • project_id INT
  • тег VARCHAR
  • made_at DATETIME

Владельцы

  • ... (теперь неактуально)

Я хотел бы получить набор проектов, и я хотел бы присоединиться только к самой новой версии для каждого проекта. Запрос DISTINCT не подходит для этой цели, поскольку он ограничивает столбцы, возвращаемые запросом, однако мне нужны все столбцы.

Вот что я придумал:

SELECT
    projects.id, projects.name, projects.owner_id
FROM
    projects
INNER JOIN
    (SELECT versions.id, versions.project_id, versions.created_at, versions.tag FROM versions ORDER BY versions.created_at DESC LIMIT 1)
ON
    projects.id = versions.project_id
WHERE
    projects.owner_id = 1

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

Но мне интересно, есть ли лучшее решение для этого? Вложенный запрос не выглядит элегантным и, вероятно, неэффективным. В первую очередь я ищу решение, совместимое с SQLite, но если есть более подходящие способы для других механизмов SQL, я тоже заинтересован в этом, поскольку в прошлом уже сталкивался с этой проблемой, например, в MySQL.

ОБНОВЛЕНИЕ: Я хотел бы дать дополнительную иллюстрацию проблемы с неправильным решением. Самый простой способ сделать это:

SELECT
    projects.id, projects.name, versions.tag, versions.created_at
FROM
    projects
INNER JOIN
    versions
ON
    projects.id = versions.project_id
WHERE
    projects.owner_id = 1
ORDER BY
    versions.created_at DESC;

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

#   id  name        tag     created_at
1   1   project1    v2.3    2018-05-08 18:33:42
2   5   project5    v4.0    2018-05-08 11:19:07
3   3   project3    v1.8    2018-05-07 21:41:49
4   5   project5    v3.18   2018-05-07 07:00:26
5   8   project8    v3.12   2018-05-06 08:59:01
6   11  project11   v1.9    2018-05-05 14:27:31
7   5   project5    v3.17   2018-05-04 11:48:22
8   1   project1    v2.2    2018-05-04 05:11:46
9   2   project2    v5.5    2018-05-03 23:08:57
10  7   project7    v6.8    2018-05-03 12:17:33

Решение неверное, поскольку оно также возвращает ненужные строки. Из этого набора данных мне понадобится строка 1, 2, 3, 5, 6, 9, 10. Потому что он упорядочен по полю versions.created_at в порядке убывания, и мне нужен первый результат, то есть самый последний из каждого проекта.

Вот почему мне понадобится какой-то «селективный LIMIT», который учитывает поле versions.project_id, так же как и запрос SELECT DISTINCT, однако мне нужно вернуть почти все поля из таблицы, не только versions.project_id.

Мне интересно, есть ли "известное" решение этой проблемы, о котором я не знаю?

1 Ответ

0 голосов
/ 08 мая 2018

Использование ROW_NUMBER с разделением по идентификатору проектов и порядку создания__, например:

SELECT *
FROM
    (SELECT
        *, ROW_NUMBER() OVER(PARTITION BY project_id ORDER BY created_at DESC) AS row_no
    FROM
        projects
    INNER JOIN
        versions ON projects.id = versions.project_id) AS tbl
WHERE row_no = 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...