Het dichtst bij een matrixkruising dat ik kan bedenken is dit:
select array_agg(e)
from (
select unnest(a1)
intersect
select unnest(a2)
) as dt(e)
Dit veronderstelt dat a1
en a2
zijn arrays met één dimensie met hetzelfde type elementen. Je zou dat kunnen inpakken in een functie zoals deze:
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;
Dan zou je dit soort dingen kunnen doen:
=> 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)
Merk op dat dit geen bepaalde volgorde in de geretourneerde array garandeert, maar je kunt dat oplossen als je erom geeft. Dan zou je je eigen verzamelfunctie kunnen maken:
-- 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[]
);
En nu zien we waarom array_intersect
doet grappige en ietwat onhandige dingen met NULL's. We hebben een beginwaarde nodig voor de aggregatie die zich gedraagt als de universele set en daarvoor kunnen we NULL gebruiken (ja, dit ruikt een beetje vreemd, maar ik kan niets beters bedenken).
Als dit alles eenmaal op zijn plaats is, kun je het volgende doen:
> 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)
Niet bepaald eenvoudig of efficiënt, maar misschien een redelijk uitgangspunt en beter dan helemaal niets.
Nuttige referenties:
array_agg
- aggregaat maken
- functie maken
- PL/pgSQL
unnest