Postgres 9.4 oder höher
Verwenden Sie WITH ORDINALITY
für satzrückgebende Funktionen:
Wenn eine Funktion im FROM
-Klausel wird durch WITH ORDINALITY
angehängt , einbigint
Spalte wird an die Ausgabe angehängt, die bei 1 beginnt und für jede Zeile der Ausgabe der Funktion um 1 erhöht wird. Dies ist am nützlichsten im Fall von Set-Rückgabefunktionen wie unnest()
.
In Kombination mit LATERAL
Funktion in pg 9.3+, und laut diesem Thread zu pgsql-hackers kann die obige Abfrage jetzt geschrieben werden als:
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 das keine Rolle spielt, können Sie dieses ansonsten äquivalente, weniger ausführliche verwenden Form mit einem impliziten 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 sein):
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 Tabelle und Spalten-Alias. Der Standardname der hinzugefügten Ordinalitätsspalte ist ordinality
. Aber es ist besser (sicherer, sauberer), explizite Spaltenaliase und Tabellenqualifizierungsspalten hinzuzufügen.
Postgres 8.4–9.3
Mit row_number() OVER (PARTITION BY id ORDER BY elem)
Sie erhalten Zahlen gemäß der Sortierreihenfolge, nicht die Ordnungszahl der ursprünglichen Ordnungsposition in der Zeichenfolge.
Sie können ORDER BY
einfach weglassen :
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 fehlgeschlagen ist, sagt PostgreSQL nichts über die Reihenfolge der Zeilen ohne ORDER BY
aus . Es funktioniert aufgrund eines Implementierungsdetails.
Um Ordnungszahlen zu garantieren 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;
Zugehörige Antwort auf dba.SE:
- Wie bewahrt man die ursprüngliche Reihenfolge der Elemente in einem nicht verschachtelten Array?
Postgres 8.1–8.4
Keine dieser Funktionen ist noch verfügbar: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 Ordinalpositionen der Elemente abweichen kann. Betrachten Sie diese Demo mit erweiterter 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[]) -- short for: '[1:3]={a,b,c}'
, (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:
- Normalisieren Sie Array-Indizes für eindimensionale Arrays, sodass sie mit 1 beginnen