Det närmaste en array-korsning jag kan komma på är detta:
select array_agg(e)
from (
select unnest(a1)
intersect
select unnest(a2)
) as dt(e)
Detta förutsätter att a1
och a2
är endimensionella arrayer med samma typ av element. Du kan slå in det i en funktion ungefär så här:
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;
Då kan du göra så här:
=> 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)
Observera att detta inte garanterar någon speciell ordning i den returnerade arrayen men du kan fixa det om du bryr dig om det. Sedan kan du skapa din egen aggregatfunktion:
-- 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[]
);
Och nu ser vi varför array_intersect
gör roliga och lite kluriga saker med NULLs. Vi behöver ett initialt värde för aggregeringen som beter sig som den universella uppsättningen och vi kan använda NULL för det (ja, det här luktar lite illa men jag kan inte komma på något bättre från mitt huvud).
När allt detta är på plats kan du göra så här:
> 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)
Inte direkt enkelt eller effektivt men kanske en rimlig utgångspunkt och bättre än ingenting alls.
Användbara referenser:
array_agg
- skapa aggregat
- skapa funktion
- PL/pgSQL
unnest