2009-09-10 7 views
1

Je releases ce tableau dans une base de données SQLite3, répertoriant chaque version publiée d'une application:Rejoindre une sous-requête limitée?

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

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

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

Je veux afficher le nom de l'application et la nouvelle version, où « les plus récents » signifie (a) le plus récent release_date, et s'il y a des doublons, (b) le plus release_id .

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 sûr que ORDER BY applique à toute requête SELECT, et si je quitte la clause WHERE, elle retourne encore une seule ligne.

Il s'agit d'une requête ponctuelle sur une petite base de données, donc les requêtes lentes, les tables temporaires, etc. vont bien - je ne peux tout simplement pas me familiariser avec SQL.

Répondre

1

Ceci est facile à faire avec la fonction analytique ROW_NUMBER(), que je suppose que sqlite3 ne supporte pas. Mais vous pouvez le faire d'une manière qui est un peu plus souple que ce qui est donné 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 aviez plusieurs colonnes de commande qui définissent « le dernier » MAX ne fonctionne pas pour vous , mais vous pouvez modifier la sous-requête EXISTS pour capturer la signification plus compliquée de "latest".

+0

Je l'aime, et je comprends même - merci! –

0

Il est laid, 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 ya un moyen d'obtenir ces deux colonnes dans un select intégré, mais je ne sais pas.

0

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 
1

Il s'agit du problème «le plus grand N par groupe». Il arrive plusieurs fois par semaine sur StackOverflow.

J'utilise habituellement une solution comme celle Kass @ Steve answer, mais je le fais sans sous-requêtes (je suis entré dans l'habitude il y a quelques années avec MySQL 4.0, qui ne prend pas en charge 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, cette optimisation est probablement identique à la syntaxe NOT EXISTS. Vous pouvez analyser la requête avec EXPLAIN pour vous assurer.


Re votre commentaire, vous pouvez simplement passer le test release_date car release_id est tout aussi utile pour établir l'ordre chronologique des rejets, et je suppose qu'il est assuré d'être unique, donc cela simplifie 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; 
+0

Il s'avère que certaines des "dates de publication" sont NULL, et cela ne les aime pas ... mais c'est le plus proche de ma représentation mentale, donc ça va m'aider à comprendre comment ces différentes requêtes se lient les unes aux autres. Merci! –

0

Deuxième tentative d'erreur.En supposant que les ID augmentent de façon monotone et le débordement n'est pas un occurance probablement, vous pouvez ignorer la date et juste 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);