PostgreSQL中多个数组的交集

Dan*_*bbs 9 sql arrays postgresql intersection aggregate-functions

我有一个视图定义为:

 CREATE VIEW View1 AS 
 SELECT Field1, Field2, array_agg(Field3) AS AggField 
 FROM Table1 
 GROUP BY Field1, Field2;
Run Code Online (Sandbox Code Playgroud)

我想要做的是获得数组的交集,AggField例如:

SELECT intersection(AggField) FROM View1 WHERE Field2 = 'SomeValue';
Run Code Online (Sandbox Code Playgroud)

这是可能的,还是有更好的方法来实现我想要的?

mu *_*ort 18

我能想到的最接近阵列交叉点的是:

select array_agg(e)
from (
    select unnest(a1)
    intersect
    select unnest(a2)
) as dt(e)
Run Code Online (Sandbox Code Playgroud)

这假定a1a2是具有相同类型元素的单维数组.你可以把它包装成一个像这样的函数:

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;
Run Code Online (Sandbox Code Playgroud)

然后你可以做这样的事情:

=> 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)
Run Code Online (Sandbox Code Playgroud)

请注意,这并不保证返回数组中的任何特定顺序,但如果您关心它,则可以修复它.然后你可以创建自己的聚合函数:

-- 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[]
);
Run Code Online (Sandbox Code Playgroud)

而现在我们看到为什么array_intersect有趣的和有点kludgey事情与NULLs.我们需要一个聚合的初始值,其行为类似于通用集合,我们可以使用NULL(是的,这闻起来有点偏,但我想不出更好的东西).

完成所有这些后,您可以执行以下操作:

> 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)
Run Code Online (Sandbox Code Playgroud)

不是简单或有效,但可能是一个合理的起点,总比没有好.

有用的参考:

  • 或者:安装提供交集运算符 (`&`) 的 intarray 扩展 (2认同)