Pregunta

Tengo esta tabla releases en una base de datos SQLite3, que enumera cada versión lanzada de una aplicación:

|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|

Entonces, para cada app_id, habrá varias filas. Tengo otra tabla, aplicaciones :

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

Deseo mostrar el nombre de la aplicación y la versión más reciente, donde " más reciente " significa (a) el último release_date, y si hay duplicados, (b) el mayor release_id.

Puedo hacer esto para una aplicación individual:

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

pero, por supuesto, ORDER BY se aplica a toda la consulta SELECT, y si omito la cláusula WHERE, todavía devuelve solo una fila.

Es una consulta de una sola vez en una base de datos pequeña, por lo que las consultas lentas, las tablas temporales, etc. están bien. Simplemente no puedo entender el modo SQL para hacer esto.

¿Fue útil?

Solución

Esto es fácil de hacer con la función analítica ROW_NUMBER (), que supongo que sqlite3 no admite. Pero puede hacerlo de una manera un poco más flexible que lo que se da en las respuestas anteriores:

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
)

Por ejemplo, si tenía varias columnas de pedido que definen " último, " MAX no funcionaría para usted, pero puede modificar la subconsulta EXISTS para capturar el significado más complicado de " más reciente. & Quot;

Otros consejos

Este es el " mayor N por grupo " problema. Viene varias veces por semana en StackOverflow.

Usualmente uso una solución como la de @Steve Kass ' respuesta , pero lo hago sin subconsultas (hace años que adquirí el hábito con MySQL 4.0, que no admitía subconsultas):

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;

Internamente, esto probablemente se optimiza de manera idéntica a la sintaxis NOT EXISTS . Puede analizar la consulta con EXPLAIN para asegurarse.


Re su comentario, podría omitir la prueba para release_date porque release_id es igual de útil para establecer el orden cronológico de los lanzamientos, y asumo que está garantizado que será único, por lo que esto simplifica la consulta:

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;

Es feo, pero creo que funcionará

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

Espero que haya alguna forma de obtener ambas columnas en una selección incrustada, pero no lo sé.

Prueba:

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

Err segundo intento. Asumiendo que las ID están aumentando monotónicamente y que no es probable que se produzca un desbordamiento, puede ignorar la fecha y simplemente hacer:

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);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top