如何仅挑选两个数组之间不匹配的元素。如何比较两个数组并只选取不匹配的元素在postgres中
实施例:
base_array [12,3,5,7,8]
temp_array [3,7,8]
所以我在这里要比较两个阵列和删除基本阵列的匹配元素。
现在base_array应该像[12,5]
如何仅挑选两个数组之间不匹配的元素。如何比较两个数组并只选取不匹配的元素在postgres中
实施例:
base_array [12,3,5,7,8]
temp_array [3,7,8]
所以我在这里要比较两个阵列和删除基本阵列的匹配元素。
现在base_array应该像[12,5]
的contrib/intarray模块提供了这个功能 - 为整数数组,反正。对于其他数据类型,您可能需要编写自己的函数(或修改intarray提供的函数)。
select array_agg(elements)
from (
select unnest(array[12,3,5,7,8])
except
select unnest(array[3,7,8])
) t (elements)
我会用数组运算符来处理这个问题。
select array(select unnest(:arr1) except select unnest(:arr2));
如果:arr1和arr2不相交,则使用array_agg()会导致null。
让我们试试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微秒......
我已经构建了一套函数来处理这些类型的问题: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]
干得好!感谢分享! –
如@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);
阵列的顺序产生不同的结果在这里:select array(除非选择unnest(ARRAY ['1','2'])),否则选择unnest(ARRAY ['1']))返回空列表,但选择数组(选择unnest(ARRAY ['1','2 ']),除了select unnest(ARRAY ['1']))返回{2}。 – Brady
@Brady:应该,不是吗? '{1} - {1,2} = {}','{1,2} - {1} = {2}'。 –
只是为了强调这个函数不稳定,在':arr1'中的顺序不会被保留。感谢分享这一行。 – jlandercy