Postgres 9.4 oder höher
Verwendung WITH ORDINALITY
für Set-Return-Funktionen:
Wenn eine Funktion in der FROM
Klausel mit einem Suffix versehen wird WITH ORDINALITY
, wird eine
bigint
Spalte an die Ausgabe angehängt, die bei 1 beginnt und für jede Zeile der Funktionsausgabe um 1 erhöht wird. Dies ist am nützlichsten bei gesetzten Rückgabefunktionen wie z unnest()
.
In Kombination mit der LATERAL
Funktion in Seite 9.3+ und gemäß diesem Thread zu pgsql-Hackern kann die obige Abfrage jetzt wie folgt geschrieben werden:
SELECT t.id, a.elem, a.nr
FROM tbl AS t
LEFT JOIN LATERAL unnest(string_to_array(t.elements, ','))
WITH ORDINALITY AS a(elem, nr) ON TRUE;
LEFT JOIN ... ON TRUE
behält alle Zeilen in der linken Tabelle bei, auch wenn der Tabellenausdruck rechts keine Zeilen zurückgibt. Wenn dies kein Problem darstellt, können Sie diese ansonsten äquivalente, weniger ausführliche Form mit einem impliziten Wert verwenden CROSS JOIN LATERAL
:
SELECT t.id, a.elem, a.nr
FROM tbl t, unnest(string_to_array(t.elements, ',')) WITH ORDINALITY a(elem, nr);
Oder einfacher, wenn es auf einem tatsächlichen Array basiert ( arr
eine Array-Spalte):
SELECT t.id, a.elem, a.nr
FROM tbl t, unnest(t.arr) WITH ORDINALITY a(elem, nr);
Oder sogar mit minimaler Syntax:
SELECT id, a, ordinality
FROM tbl, unnest(arr) WITH ORDINALITY a;
a
ist automatisch Tabellen- und Spaltenalias. Der Standardname der hinzugefügten Ordinalitätsspalte lautet ordinality
. Es ist jedoch besser (sicherer, sauberer), explizite Spaltenaliasnamen und Tabellenqualifizierungsspalten hinzuzufügen.
Postgres 8.4 - 9.3
Mit erhalten row_number() OVER (PARTITION BY id ORDER BY elem)
Sie Zahlen gemäß der Sortierreihenfolge, nicht die Ordnungszahl der ursprünglichen Ordnungsposition in der Zeichenfolge.
Sie können einfach weglassen ORDER BY
:
SELECT *, row_number() OVER (PARTITION by id) AS nr
FROM (SELECT id, regexp_split_to_table(elements, ',') AS elem FROM tbl) t;
Während dies normalerweise funktioniert und ich noch nie gesehen habe, dass es bei einfachen Abfragen fehlschlägt, behauptet PostgreSQL nichts bezüglich der Reihenfolge der Zeilen ohne ORDER BY
. Es funktioniert aufgrund eines Implementierungsdetails.
So garantieren Sie die Ordnungszahl von Elementen in der durch Leerzeichen getrennten Zeichenfolge :
SELECT id, arr[nr] AS elem, nr
FROM (
SELECT *, generate_subscripts(arr, 1) AS nr
FROM (SELECT id, string_to_array(elements, ' ') AS arr FROM tbl) t
) sub;
Oder einfacher, wenn es auf einem tatsächlichen Array basiert :
SELECT id, arr[nr] AS elem, nr
FROM (SELECT *, generate_subscripts(arr, 1) AS nr FROM tbl) t;
Verwandte Antwort auf dba.SE:
Postgres 8.1 - 8.4
Keine dieser Funktionen stehen zur Verfügung, doch: RETURNS TABLE
, generate_subscripts()
, unnest()
, array_length()
. Aber das funktioniert:
CREATE FUNCTION f_unnest_ord(anyarray, OUT val anyelement, OUT ordinality integer)
RETURNS SETOF record
LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1
FROM generate_series(array_lower($1,1), array_upper($1,1)) i';
Beachten Sie insbesondere, dass der Array-Index von den Ordnungspositionen der Elemente abweichen kann. Betrachten Sie diese Demo mit einer erweiterten Funktion :
CREATE FUNCTION f_unnest_ord_idx(anyarray, OUT val anyelement, OUT ordinality int, OUT idx int)
RETURNS SETOF record
LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1, i
FROM generate_series(array_lower($1,1), array_upper($1,1)) i';
SELECT id, arr, (rec).*
FROM (
SELECT *, f_unnest_ord_idx(arr) AS rec
FROM (VALUES (1, '{a,b,c}'::text[])
, (2, '[5:7]={a,b,c}')
, (3, '[-9:-7]={a,b,c}')
) t(id, arr)
) sub;
id | arr | val | ordinality | idx
1 | {a,b,c} | a | 1 | 1
1 | {a,b,c} | b | 2 | 2
1 | {a,b,c} | c | 3 | 3
2 | [5:7]={a,b,c} | a | 1 | 5
2 | [5:7]={a,b,c} | b | 2 | 6
2 | [5:7]={a,b,c} | c | 3 | 7
3 | [-9:-7]={a,b,c} | a | 1 | -9
3 | [-9:-7]={a,b,c} | b | 2 | -8
3 | [-9:-7]={a,b,c} | c | 3 | -7
Vergleichen Sie:
WITH ORDINALITY
bevorzugt wirdgenerate_subscripts()
? Es sieht für michgenerate_subscripts()
besser aus, da es die tatsächliche Elementposition im Array anzeigt. Dies ist zum Beispiel nützlich, wenn Sie das Array aktualisieren ... sollte ichWITH ORDINALITY
stattdessen verwenden?WITH ORDINALITY
ist die allgemeine Lösung, um Zeilennummern für jede festgelegte Rückgabefunktion in einer SQL-Abfrage abzurufen. Es ist der schnellste, zuverlässigste Weg , und es ist auch noch perfekt für 1-dimenstional, 1-basierte Arrays (Standard für Postgres - Arrays arbeiten betrachten dies ). Wenn Sie mit einer anderen Art von Arrays arbeiten (die meisten Leute tun dies nicht) und tatsächlich die ursprünglichen Indizes beibehalten / damit arbeiten müssen,generate_subscripts()
ist dies der richtige Weg. Aberunnest()
flacht zunächst alles ab ...Table functions appearing in FROM can also be preceded by the key word LATERAL, but for functions the key word is optional; the function's arguments can contain references to columns provided by preceding FROM items in any case.
Versuchen:
select v.*, row_number() over (partition by id order by elem) rn from (select id, unnest(string_to_array(elements, ',')) AS elem from myTable) v
quelle
Verwenden Sie Funktionen zum Generieren von Indizes .
http://www.postgresql.org/docs/current/static/functions-srf.html#FUNCTIONS-SRF-SUBSCRIPTS
Zum Beispiel:
SELECT id , elements[i] AS elem , i AS nr FROM ( SELECT id , elements , generate_subscripts(elements, 1) AS i FROM ( SELECT id , string_to_array(elements, ',') AS elements FROM myTable ) AS foo ) bar ;
Einfacher:
SELECT id , unnest(elements) AS elem , generate_subscripts(elements, 1) AS nr FROM ( SELECT id , string_to_array(elements, ',') AS elements FROM myTable ) AS foo ;
quelle
Wenn die Reihenfolge der Elemente nicht wichtig ist, können Sie
select id, elem, row_number() over (partition by id) as nr from ( select id, unnest(string_to_array(elements, ',')) AS elem from myTable ) a
quelle
unnest2()
als ÜbungÄltere Versionen vor pg v8.4 benötigen eine benutzerdefinierte
unnest()
. Wir können diese alte Funktion anpassen, um Elemente mit einem Index zurückzugeben:CREATE FUNCTION unnest2(anyarray) RETURNS setof record AS $BODY$ SELECT $1[i], i FROM generate_series(array_lower($1,1), array_upper($1,1)) i; $BODY$ LANGUAGE sql IMMUTABLE;
quelle
RETURNS TABLE
. Ich habe meiner Antwort ein Kapitel hinzugefügt, in dem eine Lösung besprochen wird.setof record
.