Ich arbeite mit PostgreSQL 9.4.
Ich habe eine Tabelle, die die folgenden Einträge enthält:
id | postcode | date_created
---+----------+-----------------
14 | al2 2qp | 2015-09-23 14:46:57
14 | al2 2qp | 2015-09-23 14:51:07
14 | sp2 8ag | 2015-09-23 14:56:11
14 | se4 | 2015-09-23 16:12:05
17 | e2 | 2015-09-23 16:15:35
17 | fk20 8ru | 2015-09-23 16:28:35
17 | fk20 8ru | 2015-09-23 16:35:51
17 | se2 | 2015-09-23 16:36:17
17 | fk20 8ru | 2015-09-23 16:36:22
17 | fk20 8ru | 2015-09-23 16:37:04
17 | se1 | 2015-09-23 16:37:11
17 | fk20 8ru | 2015-09-23 16:37:15
17 | se1 8ga | 2015-09-24 09:52:46
17 | se1 | 2015-09-24 10:01:19
17 | hp27 9rz | 2015-09-24 10:05:27
17 | hp27 9rz | 2015-09-24 10:05:29
17 | se1 | 2015-09-24 10:19:46
14 | tn21 8qb | 2015-09-24 14:49:05
14 | tn21 8qb | 2015-09-24 15:42:45
14 | tn21 8qb | 2015-09-24 17:38:06
14 | n4 1ny | 2015-09-25 14:49:10
Was ich erreichen möchte, ist eine Abfrage, die die 5 neuesten eindeutigen Postleitzahlendatensätze für jede ID zurückgibt :
id | postcode
---+---------
14 | n4 1ny
14 | tn21 8qb
14 | se4
14 | sp2 8ag
14 | al2 2qp
17 | se1
17 | hp27 9rz
17 | se1 8ga
17 | fk20 8ru
17 | se2
Was wäre der beste Weg, um dies zu erreichen? Ich habe mit Unterabfragen herumgespielt, aber immer wieder auf Wände gestoßen, wenn es darum geht, sie zu bestellen, während ich ein DISTINCT
und mache GROUP BY
.
postgresql
greatest-n-per-group
distinct
RoboBex
quelle
quelle
\d tbl
in psql erhalten.Antworten:
Es gibt wahrscheinlich viele Möglichkeiten, dies zu tun. Das erste, was mir in den Sinn kommt, ist die Verwendung von Fensterfunktionen:
Test bei SQLfiddle .
Wenn es Bindungen gibt, sagen wir die 5., 6. und 7.
postcode
für eineid
haben die gleichendate_created
, wird nur eine von ihnen (Auswahl wird willkürlich sein) in den Ergebnissen sein. Wenn Sie in diesen Fällen alle gebundenen Postleitzahlen möchten, verwenden SieRANK()
stattdessen anstelle vonROW_NUMBER()
.Eine andere Möglichkeit ist die Verwendung der
LATERAL
Syntax. Ich bin mir nicht sicher, welches effizienter sein wird. Es wird wahrscheinlich von der Werteverteilung der beiden Spalten (id
undpostcode
) abhängen , dh wie viele unterschiedliche IDs in der gesamten Tabelle, wie viele unterschiedliche Postleitzahlen pro ID und wie viele Zeilen pro (ID) , Postleitzahl) Kombinationen.Ein Index hinzuzufügen
(id, postcode, date_created)
wäre auch eine gute Idee - oder weiter(id, postcode, date_created DESC)
.quelle
Normalerweise haben Sie eine andere Tabelle (nennen wir sie
tbl
) mit allen unterschiedlichenid
Werten in separaten Zeilen. Wenn Sie dies nicht tun, erstellen Sie es:Oder ersetzen Sie die
tbl
unten stehende Abfrage durch dieselbeSELECT
wie die Unterabfrage, aber das ist (viel) teurer.Wenn es mehrere Zeilen pro Zeile geben kann
id
, sollte ein rekursiver CTE am schnellsten sein:Angenommen
postcode
,text
odervarchar
. Bei dieser speziellen Abfrage können Probleme auftreten, wennpostcode
Typmodifikatoren (ähnlichvarchar(50)
oder ähnlich) vorhanden sind:Ein Index für
(id, date_created)
ist für die Leistung bei großen Tabellen von entscheidender Bedeutung:SQL Fiddle.
Sie können
NULLS LAST
überall überspringen , wenn diesdate_created
definiert istNOT NULL
.Wenn deutlich mehr als 5 Zeilen pro
id
a rare Fall @ ypercube der Anfragen wird schneller sein. Test mitEXPLAIN ANALYZE
.Der Unterschied: Mein rCTE ist mit mehr Overhead verbunden, aber die Leistung wird kaum von älteren überschüssigen Zeilen beeinflusst (diese werden in der Abfrage nicht berührt). Beide Abfragen von @ ypercube haben weniger Overhead, werden jedoch langsamer mit mehr Zeilen pro
id
.Grundlagen mit Links und mehr Erklärung:
Wenn Sie keinen Tisch haben
tbl
, können Sie eine ähnliche Technik verwenden, um sichid
vonpostcode
der ersten zu unterscheiden:quelle