2011-06-30 22 views

回答

2

contrib/intarray模块提供了这个功能 - 为整数数组,反正。对于其他数据类型,您可能需要编写自己的函数(或修改intarray提供的函数)。

17
select array_agg(elements) 
from (
    select unnest(array[12,3,5,7,8]) 
    except 
    select unnest(array[3,7,8]) 
) t (elements) 
13

我会用数组运算符来处理这个问题。

select array(select unnest(:arr1) except select unnest(:arr2)); 

如果:arr1和arr2不相交,则使用array_agg()会导致null。

+0

阵列的顺序产生不同的结果在这里:select array(除非选择unnest(ARRAY ['1','2'])),否则选择unnest(ARRAY ['1']))返回空列表,但选择数组(选择unnest(ARRAY ['1','2 ']),除了select unnest(ARRAY ['1']))返回{2}。 – Brady

+4

@Brady:应该,不是吗? '{1} - {1,2} = {}','{1,2} - {1} = {2}'。 –

+0

只是为了强调这个函数不稳定,在':arr1'中的顺序不会被保留。感谢分享这一行。 – jlandercy

7

让我们试试UNNEST()/除外:

EXPLAIN ANALYZE SELECT array(select unnest(ARRAY[1,2,3,n]) EXCEPT SELECT unnest(ARRAY[2,3,4,n])) FROM generate_series(1,10000) n; 
Function Scan on generate_series n (cost=0.00..62.50 rows=1000 width=4) (actual time=1.373..140.969 rows=10000 loops=1) 
    SubPlan 1 
    -> HashSetOp Except (cost=0.00..0.05 rows=1 width=0) (actual time=0.011..0.011 rows=1 loops=10000) 
      -> Append (cost=0.00..0.04 rows=2 width=0) (actual time=0.002..0.008 rows=8 loops=10000) 
       -> Subquery Scan "*SELECT* 1" (cost=0.00..0.02 rows=1 width=0) (actual time=0.002..0.003 rows=4 loops=10000) 
         -> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.002 rows=4 loops=10000) 
       -> Subquery Scan "*SELECT* 2" (cost=0.00..0.02 rows=1 width=0) (actual time=0.001..0.003 rows=4 loops=10000) 
         -> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.002 rows=4 loops=10000) 
Total runtime: 142.531 ms 

而且intarray特殊的运算符:

EXPLAIN ANALYZE SELECT ARRAY[1,2,3,n] - ARRAY[2,3,4,n] FROM generate_series(1,10000) n; 
Function Scan on generate_series n (cost=0.00..15.00 rows=1000 width=4) (actual time=1.338..11.381 rows=10000 loops=1) 
Total runtime: 12.306 ms 

基线:

EXPLAIN ANALYZE SELECT ARRAY[1,2,3,n], ARRAY[2,3,4,n] FROM generate_series(1,10000) n; 
Function Scan on generate_series n (cost=0.00..12.50 rows=1000 width=4) (actual time=1.357..7.139 rows=10000 loops=1) 
Total runtime: 8.071 ms 

每个阵列相交时间

intarray -   : 0.4 µs 
unnest()/intersect : 13.4 µs 

当然的intarray方式快得多,但我发现它惊人的,所以Postgres不能扎普依赖子查询(包含哈希和其他的东西)的13.4微秒......

6

我已经构建了一套函数来处理这些类型的问题:https://github.com/JDBurnZ/anyarray

最大的问题是这些函数适用于所有数据类型,而不是JUST整数,因为intarray仅限于。

装载在加载从GitHub的SQL文件中定义的功能后,所有你需要做的是:

SELECT 
    ANYARRAY_DIFF(
    ARRAY[12, 3, 5, 7, 8], 
    ARRAY[3, 7, 8] 
) 

返回类似的东西来:ARRAY[12, 5]

如果你还需要退回值进行排序:

SELECT 
    ANYARRAY_SORT(
    ANYARRAY_DIFF(
     ARRAY[12, 3, 5, 7, 8], 
     ARRAY[3, 7, 8] 
    ) 
) 

正好返回:ARRAY[5, 12]

+2

干得好!感谢分享! –

0

如@a_horse_with_no_name I所述将创建使用相同的逻辑除外的函数:

CREATE FUNCTION array_subtract(a1 int[], a2 int[]) RETURNS int[] AS $$ 
DECLARE 
    ret int[]; 
BEGIN 
    IF a1 is null OR a2 is null THEN 
     return a1; 
    END IF; 
    SELECT array_agg(e) INTO ret 
    FROM (
     SELECT unnest(a1) 
     EXCEPT 
     SELECT unnest(a2) 
    ) AS dt(e); 
    RETURN ret; 
END; 
$$ language plpgsql; 

然后,可以使用该功能来进行相应的更改base_array变量:

base_array := array_subtract(base_array, temp_array); 
相关问题