2011-06-30 43 views

Trả lời

2

Module contrib/intarray cung cấp chức năng này - cho mảng các số nguyên, dù sao. Đối với các kiểu dữ liệu khác, bạn có thể phải viết các hàm của riêng bạn (hoặc sửa đổi các hàm được cung cấp với lớp 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

Tôi sẽ tiếp cận điều này với toán tử mảng.

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

Nếu: arr1 và: arr2 không giao nhau, sử dụng array_agg() dẫn đến giá trị rỗng.

+0

Trình tự của mảng sản xuất khác nhau kết quả ở đây: chọn mảng (chọn không cần thiết (ARRAY ['1']) ngoại trừ chọn không cần thiết (ARRAY ['1', '2'])) trả về danh sách trống nhưng chọn mảng (chọn không cần thiết (ARRAY ['1', '2 ']) ngoại trừ chọn không cần thiết (ARRAY [' 1 '])) trả về {2}. – Brady

+4

@ Brady: vì nó phải không? '{1} - {1,2} = {}', '{1,2} - {1} = {2}'. –

+0

Chỉ cần nhấn mạnh rằng hàm này không ổn định, thứ tự trong ': arr1' không được giữ nguyên. Cảm ơn bạn đã chia sẻ một lớp lót này. – jlandercy

7

Hãy thử unnest()/trừ:

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 

Và các nhà điều hành đặc biệt 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 

cơ bản:

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 

Thời gian cho mỗi giao lộ mảng:

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

Tất nhiên cách intarray là nhanh hơn nhiều, nhưng tôi thấy nó tuyệt vời mà postgres có thể hạ gục một subquery phụ thuộc (trong đó có chứa một hash và các công cụ khác) trong 13,4 ms ...

6

tôi đã xây dựng một bộ các chức năng để giải quyết cụ thể với các loại vấn đề sau: https://github.com/JDBurnZ/anyarray

Điều quan trọng nhất là các hàm này hoạt động trên TẤT CẢ các loại dữ liệu, không phải là số nguyên JUST, là intarray bị giới hạn.

Sau khi tải nạp các chức năng được xác định trong các tập tin SQL từ GitHub, tất cả các bạn cần phải làm là:

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

Returns một cái gì đó tương tự như: ARRAY[12, 5]

Nếu bạn cũng cần phải trả lại giá trị được sắp xếp:

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

Returns chính xác: ARRAY[5, 12]

+2

Công việc tuyệt vời! cám ơn vì đã chia sẻ! –

0

tôi sẽ tạo ra một chức năng sử dụng cùng một ngoại trừ logic như được mô tả bởi @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; 

Sau đó, bạn có thể sử dụng chức năng này để thay đổi biến base_array bạn cho phù hợp:

base_array := array_subtract(base_array, temp_array); 
Các vấn đề liên quan