如何比较两个数组并在postgres中仅选择非匹配元素

ggv*_*vkk 28 postgresql

如何只选择两个数组之间的非匹配元素.

例:

base_array [12,3,5,7,8]
temp_array [3,7,8]
Run Code Online (Sandbox Code Playgroud)

所以在这里我要比较两个数组并从基础数组中删除匹配的元素.

现在base_array应该是这样的 [12,5]

Den*_*rdy 33

我将使用数组运算符来解决这个问题.

select array(select unnest(:arr1) except select unnest(:arr2));
Run Code Online (Sandbox Code Playgroud)

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

  • @Brady:应该,不是吗?`{1} - {1,2} = {}`,`{1,2} - {1} = {2}`. (5认同)

a_h*_*ame 22

select array_agg(elements)
from (
  select unnest(array[12,3,5,7,8])
  except
  select unnest(array[3,7,8])
) t (elements)
Run Code Online (Sandbox Code Playgroud)


Jos*_*rns 10

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

最重要的是这些函数适用于所有数据类型,而不是JUST整数,intarray仅限于此.

加载从GitHub加载这些SQL文件中定义的函数后,您需要做的就是:

SELECT
  ANYARRAY_DIFF(
    ARRAY[12, 3, 5, 7, 8],
    ARRAY[3, 7, 8]
  )
Run Code Online (Sandbox Code Playgroud)

返回类似于: ARRAY[12, 5]

如果还需要返回已排序的值:

SELECT
  ANYARRAY_SORT(
    ANYARRAY_DIFF(
      ARRAY[12, 3, 5, 7, 8],
      ARRAY[3, 7, 8]
    )
  )
Run Code Online (Sandbox Code Playgroud)

完全返回: ARRAY[5, 12]


peu*_*feu 8

让我们尝试不必要的()/除外:

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

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

基线:

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

每个阵列交叉时间:

intarray -           :  0.4 µs
unnest() / intersect : 13.4 µs
Run Code Online (Sandbox Code Playgroud)

当然,intarray的方式要快得多,但我发现postgres可以在13.4μs中删除一个依赖子查询(包含一个哈希和其他东西),真是太棒了......


Fli*_*mzy 1

无论如何, contrib/intarray模块为整数数组提供了此功能。对于其他数据类型,您可能必须编写自己的函数(或修改 intarray 提供的函数)。