sql >> Base de Datos >  >> RDS >> PostgreSQL

Intersección de múltiples arreglos en PostgreSQL

Lo más parecido a una intersección de matrices que se me ocurre es esto:

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

Esto supone que a1 y a2 son matrices de una sola dimensión con el mismo tipo de elementos. Podrías envolver eso en una función como esta:

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;

Entonces podrías hacer cosas como esta:

=> 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)

Tenga en cuenta que esto no garantiza ningún orden en particular en la matriz devuelta, pero puede solucionarlo si le interesa. Entonces podrías crear tu propia función agregada:

-- 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[]
);

Y ahora vemos por qué array_intersect hace cosas divertidas y algo torpes con NULL. Necesitamos un valor inicial para la agregación que se comporte como el conjunto universal y podemos usar NULL para eso (sí, esto huele un poco mal, pero no se me ocurre nada mejor).

Una vez que todo esto esté en su lugar, puede hacer cosas como esta:

> 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)

No es exactamente simple o eficiente, pero tal vez sea un punto de partida razonable y mejor que nada.

Referencias útiles:

  • array_agg
  • crear agregado
  • crear función
  • PL/pgSQL
  • unnest