Der Beitritt zu einer begrenzten Unterabfrage?
-
05-07-2019 - |
Frage
Ich habe diese releases
Tabelle in einer SQLite3 Datenbank, jede freigegebene Version einer Anwendung Listing:
|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|
Also für jeden app_id, gibt es mehrere Zeilen sein. Ich habe eine andere Tabelle, apps
:
|app_id|name |
|======|========|
| 1|Everest |
| 2|Fuji |
Ich mag den Namen der Anwendung angezeigt werden und die neueste Version, wobei „neueste“ bedeutet (a) neuester RELEASE_DATE, und wenn es Duplikate, (b) höchst release_id.
Das kann ich für eine einzelne Anwendung:
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
aber das ist natürlich ORDER BY auf die gesamte SELECT-Abfrage gilt, und wenn ich die WHERE-Klausel weglassen, es gibt nach wie vor nur eine Zeile.
Es ist eine One-Shot-Abfrage auf einer kleine Datenbank, so langsame Abfragen, temporäre Tabellen usw. ist in Ordnung - ich kann einfach nicht mein Gehirn bekommen um den SQL-Weg, dies zu tun
.Lösung
Das ist einfach mit der analytischen Funktion ROW_NUMBER () zu tun, was ich denke, sqlite3 nicht unterstützt. Aber man kann es auf eine Weise tun, die etwas flexibler ist als das, was in den früheren Antworten gegeben hat:
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
)
Zum Beispiel, wenn Sie mehrere Ordnungs Spalten haben, die „latest“ MAX definieren würde nicht für Sie arbeitet, aber man konnte ändern die EXISTS subquery die kompliziertere Bedeutung zu erfassen „latest.“
Andere Tipps
Dies ist die „größte N pro Gruppe“ -Problem. Es kommt mehrmals pro Woche auf Stackoverflow.
ich in der Regel eine Lösung, wie die in @Steve Kass' beantworten , aber ich tue es ohne Unterabfragen (ich in die Gewohnheit, vor Jahren bekam mit MySQL 4.0, den Unterabfragen nicht unterstützt):
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;
Intern dies wahrscheinlich optimiert identisch mit der NOT EXISTS
Syntax. Sie können die Abfrage analysieren mit EXPLAIN
sicher zu machen.
Re Ihren Kommentar, Sie könnten nur den Test für release_date
überspringen, weil release_id
für die Festlegung der Reihenfolge der Veröffentlichungen ebenso nützlich ist, und ich nehme an, es ist garantiert einzigartig sein, so dass dies vereinfacht die Abfrage:
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 ist hässlich, aber ich denke, es wird funktionieren
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
Ich hoffe, es gibt eine Möglichkeit, diese beiden Spalten in einem eingebetteten wählen zu bekommen, aber ich weiß es nicht.
Versuchen:
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 zweiten Versuch. Unter der Annahme, dass IDs monoton steigen und Überlauf ist kein wahrscheinliches Auftreten, können Sie das Datum ignorieren und einfach tun:
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);