2011-06-30 16 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

配列の順序が異なる生成(ARRAY ['1'、 '2']))は空リストを返しますが、配列を選択します(ARRAY ['1'、 '2']) '])は、{2}を返します。 – Brady

+4

@ブラディ:それは必要ですか? '{1} - {1,2} = {}'、 '{1,2} - {1} = {2}'です。 –

+0

この関数が安定していないことを強調すると、 ':arr1'の順序は保持されません。この1つのライナーを共有していただきありがとうございます。 – jlandercy

7

)のは(アンネストを試してみましょう/除い:

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 
0私はセットを構築してきました。もちろん、

intarray方法がはるかに高速ですが、私はそれは素晴らしいPostgresは13.4マイクロ秒に(ハッシュや他のものが含まれている)に依存するサブクエリを攻撃することができますを見つける...

6

https://github.com/JDBurnZ/anyarray

これらの機能は、すべてのデータ型で機能しますが、整数型ではなく、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によって記載されているように私は、ロジックを除いて同じを使用して関数を作成します。

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); 
関連する問題