Nejbližší věc k průsečíku pole, která mě napadá, je toto:
select array_agg(e)
from (
select unnest(a1)
intersect
select unnest(a2)
) as dt(e)
To předpokládá, že a1
a a2
jsou jednorozměrná pole se stejným typem prvků. Můžete to zabalit do funkce, která je podobná této:
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;
Pak byste mohli dělat věci jako toto:
=> 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)
Všimněte si, že to nezaručuje žádné konkrétní pořadí ve vráceném poli, ale můžete to opravit, pokud vám na tom záleží. Pak byste mohli vytvořit svou vlastní agregační funkci:
-- 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[]
);
A nyní vidíme, proč array_intersect
dělá legrační a poněkud nemotorné věci s NULL. Potřebujeme počáteční hodnotu pro agregaci, která se chová jako univerzální množina, a na to můžeme použít NULL (ano, trochu to zavání, ale nic lepšího mě z hlavy nenapadá).
Jakmile je toto vše na místě, můžete dělat věci jako:
> 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)
Není to úplně jednoduché nebo efektivní, ale možná je to rozumný výchozí bod a lepší než nic.
Užitečné odkazy:
array_agg
- vytvořit souhrn
- vytvořit funkci
- PL/pgSQL
unnest