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

Intersection de plusieurs tableaux dans PostgreSQL

La chose la plus proche d'une intersection de tableau à laquelle je puisse penser est celle-ci :

select array_agg(e)
from (
    select unnest(a1)
    intersect
    select unnest(a2)
) as dt(e)

Cela suppose que a1 et a2 sont des tableaux à une dimension avec le même type d'éléments. Vous pourriez résumer cela dans une fonction comme celle-ci :

create function array_intersect(a1 int[], a2 int[]) returns int[] as $$
declare
    ret int[];
begin
    -- The reason for the kludgy NULL handling comes later.
    if a1 is null then
        return a2;
    elseif a2 is null then
        return a1;
    end if;
    select array_agg(e) into ret
    from (
        select unnest(a1)
        intersect
        select unnest(a2)
    ) as dt(e);
    return ret;
end;
$$ language plpgsql;

Ensuite, vous pourriez faire des choses comme ceci :

=> select array_intersect(ARRAY[2,4,6,8,10], ARRAY[1,2,3,4,5,6,7,8,9,10]);
 array_intersect 
-----------------
 {6,2,4,10,8}
(1 row)

Notez que cela ne garantit aucun ordre particulier dans le tableau renvoyé, mais vous pouvez résoudre ce problème si vous vous en souciez. Ensuite, vous pouvez créer votre propre fonction d'agrégat :

-- Pre-9.1
create aggregate array_intersect_agg(
    sfunc    = array_intersect,
    basetype = int[],
    stype    = int[],
    initcond = NULL
);

-- 9.1+ (AFAIK, I don't have 9.1 handy at the moment
-- see the comments below.
create aggregate array_intersect_agg(int[]) (
    sfunc = array_intersect,
    stype = int[]
);

Et maintenant nous voyons pourquoi array_intersect fait des choses amusantes et quelque peu maladroites avec les NULL. Nous avons besoin d'une valeur initiale pour l'agrégation qui se comporte comme l'ensemble universel et nous pouvons utiliser NULL pour cela (oui, cela sent un peu mauvais, mais je ne vois rien de mieux en tête).

Une fois que tout cela est en place, vous pouvez faire des choses comme ceci :

> select * from stuff;
    a    
---------
 {1,2,3}
 {1,2,3}
 {3,4,5}
(3 rows)

> select array_intersect_agg(a) from stuff;
 array_intersect_agg 
---------------------
 {3}
(1 row)

Pas exactement simple ou efficace, mais peut-être un point de départ raisonnable et mieux que rien du tout.

Références utiles :

  • array_agg
  • créer un agrégat
  • créer une fonction
  • PL/pgSQL
  • unnest