Question

J'ai cette table releases dans une base de données SQLite3, répertoriant chaque version publiée d'une application:

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

Donc, pour chaque app_id, il y aura plusieurs lignes. J'ai une autre table, apps :

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

Je souhaite afficher le nom de l'application et la version la plus récente, où "tout récent". signifie (a) date de publication la plus récente, et s’il existe des doublons, (b) ID de publication le plus élevé.

Je peux le faire pour une application individuelle:

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

mais bien entendu, ORDER BY s’applique à l’ensemble de la requête SELECT, et si je laisse de côté la clause WHERE, elle ne renvoie toujours qu’une ligne.

Il s'agit d'une requête unique sur une petite base de données. Les requêtes lentes, les tables temporaires, etc. sont donc acceptables. Je n'arrive pas à comprendre comment SQL le fait.

Était-ce utile?

La solution

C’est facile à faire avec la fonction analytique ROW_NUMBER (), que je suppose que sqlite3 ne prend pas en charge. Mais vous pouvez le faire de manière un peu plus souple que ce qui a été dit dans les réponses précédentes:

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
)

Par exemple, si vous avez plusieurs colonnes de classement définissant le paramètre "dernière", " MAX ne fonctionnerait pas pour vous, mais vous pouvez modifier la sous-requête EXISTS pour capturer le sens plus compliqué de "dernières".

Autres conseils

C’est le "plus grand N par groupe" problème. Il arrive plusieurs fois par semaine sur StackOverflow.

J'utilise généralement une solution similaire à celle de @Steve Kass, answer , mais je le fais sans sous-requêtes (je me suis habitué il y a des années avec MySQL 4.0, qui ne supportait pas les sous-requêtes):

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;

En interne, cela optimise probablement la même chose que la syntaxe NOT EXISTS . Vous pouvez analyser la requête avec EXPLAIN pour vous en assurer.

En ce qui concerne votre commentaire, vous pouvez ignorer le test pour date_diffusion , car id_exécution est tout aussi utile pour établir l'ordre chronologique des publications, et je suppose que cela est garanti. unique, cela simplifie donc la requête:

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;

C'est moche, mais je pense que ça va marcher

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

J'espère qu'il sera possible d'obtenir ces deux colonnes en une sélection intégrée, mais je ne le sais pas.

Essayez:

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 deuxième tentative. En supposant que les identifiants augmentent de façon monotone et que les débordements ne soient pas probables, vous pouvez ignorer la date et simplement faire:

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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top