A coisa mais próxima de uma interseção de matriz que posso pensar é isso:
select array_agg(e)
from (
select unnest(a1)
intersect
select unnest(a2)
) as dt(e)
Isso pressupõe que
a1
e a2
são matrizes de dimensão única com o mesmo tipo de elementos. Você poderia embrulhar isso em uma função mais ou menos assim: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;
Então você poderia fazer coisas assim:
=> 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)
Observe que isso não garante nenhuma ordem específica na matriz retornada, mas você pode corrigir isso se se importar com isso. Então você pode criar sua própria função 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[]
);
E agora vemos porque
array_intersect
faz coisas engraçadas e um tanto estranhas com NULLs. Precisamos de um valor inicial para a agregação que se comporte como o conjunto universal e podemos usar NULL para isso (sim, isso cheira um pouco errado, mas não consigo pensar em nada melhor de cabeça). Uma vez que tudo isso está no lugar, você pode fazer coisas assim:
> 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)
Não exatamente simples ou eficiente, mas talvez um ponto de partida razoável e melhor do que nada.
Referências úteis:
array_agg
- criar agregado
- criar função
- PL/pgSQL
unnest