PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Existe-t-il quelque chose comme une fonction zip() dans PostgreSQL qui combine deux tableaux ?

Postgres 9.5 ou version ultérieure

a array_agg(array expression) :

array_agg ( anyarray ) → anyarray

Concatène tous les tableaux d'entrée dans un tableau d'une dimension supérieure. (Les entrées doivent toutes avoir la même dimensionnalité et ne peuvent pas être vides ou nulles.)

Il s'agit d'un remplacement instantané de ma fonction d'agrégation personnalisée array_agg_mult() démontré ci-dessous. Il est implémenté en C et considérablement plus rapide. Utilisez-le.

Postgres 9.4

Utilisez les ROWS FROM construction ou le unnest() mis à jour qui nécessite plusieurs tableaux pour se désimbriquer en parallèle. Chacun peut avoir une longueur différente. Vous obtenez (par documentation) :

[...] le nombre de lignes de résultat dans ce cas est celui du plus grand résultat de fonction, avec des résultats plus petits remplis de valeurs nulles pour correspondre.

Utilisez cette variante plus propre et plus simple :

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

Postgres 9.3 ou version antérieure

Zip simple()

Considérez la démo suivante pour Postgres 9.3 ou version antérieure :

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

Résultat :

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

Notez que les deux tableaux doivent avoir le même nombre d'éléments pour désimbriquer en parallèle, ou vous obtenez une jointure croisée à la place.

Vous pouvez encapsuler cela dans une fonction, si vous voulez :

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$;

Appel :

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

Même résultat.

zip() vers un tableau multidimensionnel :

Maintenant, si vous voulez agréger ce nouvel ensemble de tableaux en un seul bidimensionnel tableau, ça devient plus compliqué.

SELECT ARRAY (SELECT ...)

ou :

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

ou :

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

entraîneront tous le même message d'erreur (testé avec pg 9.1.5):

ERREUR :impossible de trouver le type de tableau pour le type de données text[]

Mais il existe un moyen de contourner ce problème, comme nous l'avons expliqué dans le cadre de cette question étroitement liée.
Créez une fonction d'agrégation personnalisée :

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

Et utilisez-le comme ceci :

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

Résultat :

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

Notez le ARRAY[] supplémentaire couche! Sans elle et juste :

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

Vous obtenez :

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

Ce qui peut être utile à d'autres fins.

Lancer une autre fonction :

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$;

Appel :

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

Résultat :

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