Det tætteste på et array skæringspunkt, som jeg kan komme i tanke om, er dette:
select array_agg(e)
from (
select unnest(a1)
intersect
select unnest(a2)
) as dt(e)
Dette forudsætter, at a1
og a2
er enkeltdimensionsarrays med den samme type elementer. Du kan pakke det ind i en funktion som denne:
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;
Så kunne du gøre ting som dette:
=> 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)
Bemærk, at dette ikke garanterer nogen bestemt rækkefølge i det returnerede array, men du kan ordne det, hvis du bekymrer dig om det. Så kan du oprette din egen aggregerede funktion:
-- 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[]
);
Og nu ser vi hvorfor array_intersect
laver sjove og lidt klodsede ting med NULLs. Vi har brug for en startværdi for aggregeringen, der opfører sig som det universelle sæt, og vi kan bruge NULL til det (ja, det lugter lidt, men jeg kan ikke komme i tanke om noget bedre fra toppen af mit hoved).
Når alt dette er på plads, kan du gøre ting som dette:
> 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)
Ikke ligefrem simpelt eller effektivt, men måske et fornuftigt udgangspunkt og bedre end slet ingenting.
Nyttige referencer:
array_agg
- opret aggregat
- opret funktion
- PL/pgSQL
unnest