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