Wie kann ich GROUP BY
eine Spalte, während nur nach einer anderen sortieren .
Ich versuche Folgendes zu tun:
SELECT dbId,retreivalTime
FROM FileItems
WHERE sourceSite='something'
GROUP BY seriesName
ORDER BY retreivalTime DESC
LIMIT 100
OFFSET 0;
Ich möchte die letzten / n / Elemente aus FileItems in absteigender Reihenfolge auswählen , wobei die Zeilen nach den DISTINCT
Werten von gefiltert werden seriesName
. Die obige Abfrage ist fehlerhaft ERROR: column "fileitems.dbid" must appear in the GROUP BY clause or be used in an aggregate function
. Ich benötige den dbid
Wert, um dann die Ausgabe dieser Abfrage zu übernehmen, und JOIN
ihn in der Quelltabelle, um den Rest der Spalten abzurufen, die ich nicht war.
Beachten Sie, dass dies im Grunde die Gestalt der folgenden Frage ist, wobei viele der überflüssigen Details aus Gründen der Klarheit entfernt wurden.
Ursprüngliche Frage
Ich habe ein System, das ich von sqlite3 auf PostgreSQL migriere, weil ich sqlite weitgehend entwachsen bin:
SELECT
d.dbId,
d.dlState,
d.sourceSite,
[snip a bunch of rows]
d.note
FROM FileItems AS d
JOIN
( SELECT dbId
FROM FileItems
WHERE sourceSite='{something}'
GROUP BY seriesName
ORDER BY MAX(retreivalTime) DESC
LIMIT 100
OFFSET 0
) AS di
ON di.dbId = d.dbId
ORDER BY d.retreivalTime DESC;
Grundsätzlich möchte ich die letzten n DISTINCT
Elemente in der Datenbank auswählen , wobei die eindeutige Einschränkung in einer Spalte und die Sortierreihenfolge in einer anderen Spalte liegt.
Leider funktioniert die obige Abfrage, obwohl sie in SQLite einwandfrei funktioniert, in PostgreSQL mit dem Fehler psycopg2.ProgrammingError: column "fileitems.dbid" must appear in the GROUP BY clause or be used in an aggregate function
.
Während das Hinzufügen dbId
zur GROUP BY-Klausel das Problem behebt (z. B. GROUP BY seriesName,dbId
), bedeutet dies leider, dass die eindeutige Filterung der Abfrageergebnisse nicht mehr funktioniert, da dbid
es sich um den Datenbankprimärschlüssel handelt und daher alle Werte unterschiedlich sind.
Nach dem Lesen der Postgres-Dokumentation gibt es SELECT DISTINCT ON ({nnn})
jedoch, dass die zurückgegebenen Ergebnisse nach sortiert werden müssen {nnn}
.
Daher zu tun , was über ich würde wollen SELECT DISTINCT ON
, ich Abfrage für alle haben würde DISTINCT {nnn}
und ihre MAX(retreivalTime)
, irgendwie wieder nach retreivalTime
eher dann {nnn}
, dann nehmen Sie die 100 größten und Abfrage der gegen den Tisch mit dem Rest der Zeilen zu erhalten, die ich seriesName
Ich möchte vermeiden, da die Datenbank ~ 175K Zeilen und ~ 14K unterschiedliche Werte in der Spalte enthält. Ich möchte nur die neuesten 100, und diese Abfrage ist etwas leistungskritisch (ich benötige Abfragezeiten <1/2 Sekunde).
Meine naive Annahme hier ist im Grunde, dass die DB einfach jede Zeile in absteigender Reihenfolge durchlaufen retreivalTime
und einfach anhalten muss, sobald sie LIMIT
Elemente gesehen hat. Eine vollständige Tabellenabfrage ist also nicht ideal, aber ich gebe nicht vor, wirklich zu verstehen, wie die Datenbank ist System optimiert intern, und ich kann dies völlig falsch angehen.
FWIW, ich verwende gelegentlich andere OFFSET
Werte, aber lange Abfragezeiten für Fälle, in denen ein Offset> ~ 500 völlig akzeptabel ist. Grundsätzlich OFFSET
handelt es sich um einen beschissenen Paging-Mechanismus, mit dem ich entkommen kann, ohne jeder Verbindung einen Bildlaufcursor zuweisen zu müssen, und ich werde ihn wahrscheinlich irgendwann noch einmal überprüfen.
Ref - Frage, die ich vor einem Monat gestellt habe und die zu dieser Abfrage geführt hat .
Ok, mehr Notizen:
SELECT
d.dbId,
d.dlState,
d.sourceSite,
[snip a bunch of rows]
d.note
FROM FileItems AS d
JOIN
( SELECT seriesName, MAX(retreivalTime) AS max_retreivalTime
FROM FileItems
WHERE sourceSite='{something}'
GROUP BY seriesName
ORDER BY max_retreivalTime DESC
LIMIT %s
OFFSET %s
) AS di
ON di.seriesName = d.seriesName AND di.max_retreivalTime = d.retreivalTime
ORDER BY d.retreivalTime DESC;
Funktioniert für die Abfrage wie beschrieben ordnungsgemäß, aber wenn ich die Klausel entferneGROUP BY
, schlägt sie fehl (in meiner Anwendung optional).
psycopg2.ProgrammingError: column "FileItems.seriesname" must appear in the GROUP BY clause or be used in an aggregate function
Ich glaube, ich verstehe grundsätzlich nicht, wie Unterabfragen in PostgreSQL funktionieren. Wo gehe ich falsch? Ich hatte den Eindruck, dass eine Unterabfrage im Grunde nur eine Inline-Funktion ist, bei der die Ergebnisse nur in die Hauptabfrage eingespeist werden.