PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Gibt es so etwas wie eine zip()-Funktion in PostgreSQL, die zwei Arrays kombiniert?

Postgres 9.5 oder höher

hat array_agg(array expression) :

array_agg ( anyarray ) → anyarray

Verkettet alle Eingabearrays zu einem Array mit einer höheren Dimension. (Die Eingaben müssen alle die gleiche Dimensionalität haben und dürfen nicht leer oder null sein.)

Dies ist ein Drop-in-Ersatz für meine benutzerdefinierte Aggregatfunktion array_agg_mult() unten demonstriert. Es ist in C implementiert und erheblich schneller. Verwenden Sie es.

Postgres 9.4

Verwenden Sie die ROWS FROM Konstrukt oder das aktualisierte unnest() wodurch mehrere Arrays parallel entschachtelt werden müssen. Jeder kann eine andere Länge haben. Sie erhalten (per Dokumentation):

[...] die Anzahl der Ergebniszeilen ist in diesem Fall die des größten Funktionsergebnisses, wobei kleinere Ergebnisse passend mit Nullwerten aufgefüllt werden.

Verwenden Sie diese sauberere und einfachere Variante:

SELECT ARRAY[a,b] AS ab
FROM   unnest('{a,b,c}'::text[] 
            , '{d,e,f}'::text[]) x(a,b);

Postgres 9.3 oder älter

Einfach zip()

Betrachten Sie die folgende Demo für Postgres 9.3 oder früher :

SELECT ARRAY[a,b] AS ab
FROM  (
   SELECT unnest('{a,b,c}'::text[]) AS a
        , unnest('{d,e,f}'::text[]) AS b
    ) x;

Ergebnis:

  ab
-------
 {a,d}
 {b,e}
 {c,f}

Beachten Sie, dass beide Arrays die gleiche Anzahl von Elementen haben müssen parallel zu entschachteln, oder Sie erhalten stattdessen einen Cross Join.

Sie können dies in eine Funktion packen, wenn Sie möchten:

CREATE OR REPLACE FUNCTION zip(anyarray, anyarray)
  RETURNS SETOF anyarray LANGUAGE SQL AS
$func$
SELECT ARRAY[a,b] FROM (SELECT unnest($1) AS a, unnest($2) AS b) x;
$func$;

Aufruf:

SELECT zip('{a,b,c}'::text[],'{d,e,f}'::text[]);

Gleiches Ergebnis.

zip() in mehrdimensionales Array:

Nun, wenn Sie aggregieren möchten diesen neuen Satz von Arrays in ein zweidimensionales -Array, wird es komplizierter.

SELECT ARRAY (SELECT ...)

oder:

SELECT array_agg(ARRAY[a,b]) AS ab
FROM  (
   SELECT unnest('{a,b,c}'::text[]) AS a
         ,unnest('{d,e,f}'::text[]) AS b
    ) x

oder:

SELECT array_agg(ARRAY[ARRAY[a,b]]) AS ab
FROM  ...

führen alle zu derselben Fehlermeldung (getestet mit Seite 9.1.5):

FEHLER:Arraytyp für Datentyp text[]

konnte nicht gefunden werden

Aber es gibt einen Weg, dies zu umgehen, wie wir unter dieser eng verwandten Frage ausgearbeitet haben.
Erstellen Sie eine benutzerdefinierte Aggregatfunktion:

CREATE AGGREGATE array_agg_mult (anyarray) (
   SFUNC    = array_cat
 , STYPE    = anyarray
 , INITCOND = '{}'
);

Und verwenden Sie es so:

SELECT array_agg_mult(ARRAY[ARRAY[a,b]]) AS ab
FROM  (
   SELECT unnest('{a,b,c}'::text[]) AS a
        , unnest('{d,e,f}'::text[]) AS b
    ) x

Ergebnis:

{{a,d},{b,e},{c,f}}

Beachten Sie das zusätzliche ARRAY[] Schicht! Ohne sie und nur:

SELECT array_agg_mult(ARRAY[a,b]) AS ab
FROM ...

Sie erhalten:

{a,d,b,e,c,f}

Was für andere Zwecke nützlich sein kann.

Rollen Sie eine andere Funktion:

CREATE OR REPLACE FUNCTION zip2(anyarray, anyarray)
  RETURNS SETOF anyarray LANGUAGE SQL AS
$func$
SELECT array_agg_mult(ARRAY[ARRAY[a,b]])
FROM (SELECT unnest($1) AS a, unnest($2) AS b) x;
$func$;

Aufruf:

SELECT zip2('{a,b,c}'::text[],'{d,e,f}'::text[]); -- or any other array type

Ergebnis:

{{a,d},{b,e},{c,f}}