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: