Вопрос

у меня есть это releases таблица в базе данных SQLite3, в которой перечислены все выпущенные версии приложения:

|release_id|release_date|app_id|
|==========|============|======|
|      1001| 2009-01-01 |     1|
|      1003| 2009-01-01 |     1|
|      1004| 2009-02-02 |     2|
|      1005| 2009-01-15 |     1|

Таким образом, для каждого app_id будет несколько строк.У меня есть еще один стол, apps:

|app_id|name    |
|======|========|
|     1|Everest |
|     2|Fuji    |

Я хочу отобразить название приложения и новейшую версию, где «новейшая» означает (а) новейшую дату_выпуска, а если есть дубликаты, (б) самый высокий Release_id.

Я могу сделать это для отдельного приложения:

SELECT apps.name,releases.release_id,releases.release_date 
  FROM apps 
  INNER JOIN releases 
    ON apps.app_id = releases.app_id
  WHERE releases.release_id = 1003
  ORDER BY releases.release_date,releases.release_id
  LIMIT 1

но, конечно, этот ORDER BY применяется ко всему запросу SELECT, и если я оставлю предложение WHERE, он все равно вернет только одну строку.

Это однократный запрос к небольшой базе данных, поэтому медленные запросы, временные таблицы и т. д.все в порядке - я просто не могу понять, как это сделать с помощью SQL.

Это было полезно?

Решение

Это легко сделать с помощью аналитической функции ROW_NUMBER (), которую, я думаю, sqlite3 не поддерживает. Но вы можете сделать это более гибким способом, чем в предыдущих ответах:

SELECT
  apps.name,
  releases.release_id,
  releases.release_date 
FROM apps INNER JOIN releases 
ON apps.app_id = releases.app_id
WHERE NOT EXISTS (
-- // where there doesn't exist a more recent release for the same app
  SELECT * FROM releases AS R
  WHERE R.app_id = apps.app_id
  AND R.release_data > releases.release_data
)

Например, если у вас было несколько столбцов заказа, которые определяют " последний, " MAX не будет работать для вас, но вы можете изменить подзапрос EXISTS, чтобы он улавливал более сложное значение "Quest; latest".

Другие советы

Это "наибольшее N на группу" проблема. Это происходит несколько раз в неделю на StackOverflow.

Обычно я использую решение, подобное тому, которое есть в ответе @Steve Kass <, но я делаю это без подзапросов (я привык к MySQL 4.0, который не поддерживал подзапросы):

SELECT a.name, r1.release_id, r1.release_date
FROM apps a
INNER JOIN releases r1
LEFT OUTER JOIN releases r2 ON (r1.app_id = r2.app_id 
  AND (r1.release_date < r2.release_date
    OR r1.release_date = r2.release_date AND r1.release_id < r2.release_id))
WHERE r2.release_id IS NULL;

Внутренне это, вероятно, оптимизирует идентично синтаксису NOT EXISTS . Вы можете проанализировать запрос с помощью EXPLAIN , чтобы убедиться в этом. <Ч>

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

SELECT a.name, r1.release_id, r1.release_date
FROM apps a
INNER JOIN releases r1
LEFT OUTER JOIN releases r2 ON (r1.app_id = r2.app_id 
  AND r1.release_id < r2.release_id)
WHERE r2.release_id IS NULL;

Это некрасиво, но я думаю, что это сработает

select apps.name, (select releases.release_id from releases where releases.app_id=apps.app_id order by releases.release_date, releases.release_id), (select releases.release_date from releases where releases.app_id=apps.app_id order by releases.release_date, releases.release_id) from apps order by apps.app_id

Я надеюсь, что есть какой-то способ объединить оба этих столбца в один встроенный выбор, но я этого не знаю.

Пытаться:

SELECT a.name,
       t.max_release_id,
       t.max_date
  FROM APPS a
  JOIN (SELECT t.app_id,
               MAX(t.release_id) 'max_release_id',
               t.max_date
          FROM (SELECT r.app_id,
                       r.release_id,
                       MAX(r.release_date) 'max_date'
                  FROM RELEASES r
              GROUP BY r.app_id, r.release_id)
      GROUP BY t.app_id, t.max_date) t

Ошибка второй попытки. Предполагая, что идентификаторы увеличиваются монотонно и переполнение не является вероятным явлением, вы можете игнорировать дату и просто сделать:

SELECT apps.name, releases.release_id, releases.release_date 
FROM apps INNER JOIN releases on apps.app_id = releases.app_id
WHERE releases.release_id IN 
(SELECT Max(release_id) FROM releases
GROUP BY app_id);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top