loại bỏ các giá trị mảng trùng lặp trong postgres


86

Tôi có một kiểu mảng bigint, làm cách nào để xóa các giá trị trùng lặp trong mảng đó?

Ví dụ: array[1234, 5343, 6353, 1234, 1234]

Tôi nên lấy array[1234, 5343, 6353, ...]

Tôi đã thử nghiệm ví dụ SELECT uniq(sort('{1,2,3,2,1}'::int[]))trong hướng dẫn postgres nhưng nó không hoạt động.

Câu trả lời:


92

Tôi đối mặt với cùng một. Nhưng một mảng trong trường hợp của tôi được tạo thông qua array_agghàm. Và may mắn thay, nó cho phép tổng hợp các giá trị DISTINCT , như:

  array_agg(DISTINCT value)

Điều này làm việc cho tôi.


5
Lưu ý rằng DISTINCT không được hỗ trợ cho các chức năng cửa sổ.
có thể nghĩ tới

anh chàng tkstrim(string_agg(distinct to_char(z.dat_codigo,'0000000000'),'')) as dat_codigo,
Fábio Zangirolami

4
select array_agg (DISTINCT Array [1,2,2,3]) cho "{{1,2,2,3}}"
user48956

@ user48956, điều đó hợp lý, khi bạn nhập một mảng làm giá trị, bạn cần đặt một cột duy nhất làm giá trị được nhóm theo truy vấn
Daniël Tulp

83

Các chức năng sort(int[])uniq(int[]) được cung cấp bởi mô-đun đóng góp intarray .

Để cho phép sử dụng nó, bạn phải cài đặt mô-đun .

Nếu bạn không muốn sử dụng mô-đun đóng góp intarray hoặc nếu bạn phải xóa các bản sao khỏi các mảng thuộc loại khác nhau, bạn có hai cách khác.

Nếu bạn có ít nhất PostgreSQL 8.4, bạn có thể tận dụng unnest(anyarray)chức năng

SELECT ARRAY(SELECT DISTINCT UNNEST('{1,2,3,2,1}'::int[]) ORDER BY 1);
 ?column? 
----------
 {1,2,3}
(1 row)

Ngoài ra, bạn có thể tạo chức năng của riêng mình để thực hiện việc này

CREATE OR REPLACE FUNCTION array_sort_unique (ANYARRAY) RETURNS ANYARRAY
LANGUAGE SQL
AS $body$
  SELECT ARRAY(
    SELECT DISTINCT $1[s.i]
    FROM generate_series(array_lower($1,1), array_upper($1,1)) AS s(i)
    ORDER BY 1
  );
$body$;

Đây là một lời gọi mẫu:

SELECT array_sort_unique('{1,2,3,2,1}'::int[]);
 array_sort_unique 
-------------------
 {1,2,3}
(1 row)

1
Giải pháp của bài toán ("loại bỏ các giá trị mảng trùng lặp") không cần phải sắp xếp . Mặc dù thường là một tính năng hữu ích, nhưng nó là không cần thiết (chi phí CPU) trong ngữ cảnh / yêu cầu này.
Peter Krauss

27

... Nơi các thư viện statandard (?) Cho loại tiện ích array_X ??

Cố gắng tìm kiếm ... Xem một số nhưng không có tiêu chuẩn:


array_distinct()Hàm đoạn mã-lib đơn giản và nhanh hơn

Đây là cách triển khai đơn giản nhất và có lẽ nhanh hơn cho array_unique()hoặc array_distinct():

CREATE FUNCTION array_distinct(anyarray) RETURNS anyarray AS $f$
  SELECT array_agg(DISTINCT x) FROM unnest($1) t(x);
$f$ LANGUAGE SQL IMMUTABLE;

LƯU Ý: nó hoạt động như mong đợi với bất kỳ kiểu dữ liệu nào, ngoại trừ với mảng mảng,

SELECT  array_distinct( array[3,3,8,2,6,6,2,3,4,1,1,6,2,2,3,99] ), 
        array_distinct( array['3','3','hello','hello','bye'] ), 
        array_distinct( array[array[3,3],array[3,3],array[3,3],array[5,6]] );
 -- "{1,2,3,4,6,8,99}",  "{3,bye,hello}",  "{3,5,6}"

"hiệu ứng phụ" là làm nổ tất cả các mảng trong một tập hợp các phần tử.

PS: với mảng JSONB hoạt động tốt,

SELECT array_distinct( array['[3,3]'::JSONB, '[3,3]'::JSONB, '[5,6]'::JSONB] );
 -- "{"[3, 3]","[5, 6]"}"

Chỉnh sửa: phức tạp hơn nhưng hữu ích, tham số "drop nulls"

CREATE FUNCTION array_distinct(
      anyarray, -- input array 
      boolean DEFAULT false -- flag to ignore nulls
) RETURNS anyarray AS $f$
      SELECT array_agg(DISTINCT x) 
      FROM unnest($1) t(x) 
      WHERE CASE WHEN $2 THEN x IS NOT NULL ELSE true END;
$f$ LANGUAGE SQL IMMUTABLE;

bạn có thể vui lòng giải thích t là gì (x) làm trong TỪ unnest ($ 1) t (x) ... cũng làm thế nào tôi có thể giữ trật tự các mặt hàng, trong đó họ chèn
abhirathore2006

@ abhirathore2006 câu trả lời này là một Wiki, bạn có thể viết các giải thích mà bạn đã đề xuất. Về "giữ trật tự", không, đó là một giải pháp phá hủy, Xem các giải pháp PLpgSQL trong trang này để bảo toàn trật tự mảng ban đầu. Nó cũng là chung của hai yêu cầu, sắp xếpphân biệt (xem thành công của câu trả lời chính ở đây và nhận xét của tôi ở đó).
Peter Krauss

không phải lo lắng, tôi đã tìm thấy giải pháp từ một nơi khác, có nghĩa là giải pháp PLSQL
abhirathore2006

13

Tôi đã tập hợp một tập hợp các thủ tục (hàm) được lưu trữ để chống lại sự thiếu xử lý mảng của PostgreSQL anyarray. Các hàm này được thiết kế để hoạt động trên mọi kiểu dữ liệu mảng chứ không chỉ số nguyên như intarray: https://www.github.com/JDBurnZ/anyarray

Trong trường hợp của bạn, tất cả những gì bạn thực sự cần là anyarray_uniq.sql. Sao chép và dán nội dung của tệp đó vào một truy vấn PostgreSQL và thực thi nó để thêm chức năng. Nếu bạn cũng cần sắp xếp mảng, hãy thêm vào anyarray_sort.sql.

Từ đó, bạn có thể tạo một truy vấn đơn giản như sau:

SELECT ANYARRAY_UNIQ(ARRAY[1234,5343,6353,1234,1234])

Trả về một cái gì đó tương tự như: ARRAY[1234, 6353, 5343]

Hoặc nếu bạn yêu cầu sắp xếp:

SELECT ANYARRAY_SORT(ANYARRAY_UNIQ(ARRAY[1234,5343,6353,1234,1234]))

Trả lại chính xác: ARRAY[1234, 5343, 6353]


13

Sử dụng DISTINCTngầm định sắp xếp mảng. Nếu thứ tự tương đối của các phần tử mảng cần được giữ nguyên trong khi loại bỏ các phần tử trùng lặp, thì hàm có thể được thiết kế như sau: (sẽ hoạt động từ 9.4 trở đi)

CREATE OR REPLACE FUNCTION array_uniq_stable(anyarray) RETURNS anyarray AS
$body$
SELECT
    array_agg(distinct_value ORDER BY first_index)
FROM 
    (SELECT
        value AS distinct_value, 
        min(index) AS first_index 
    FROM 
        unnest($1) WITH ORDINALITY AS input(value, index)
    GROUP BY
        value
    ) AS unique_input
;
$body$
LANGUAGE 'sql' IMMUTABLE STRICT;

1
câu trả lời tốt nhất! xem thêm: dba.stackexchange.com/questions/211501/…
fjsj

9

Đây là cách "nội tuyến":

SELECT 1 AS anycolumn, (
  SELECT array_agg(c1)
  FROM (
    SELECT DISTINCT c1
    FROM (
      SELECT unnest(ARRAY[1234,5343,6353,1234,1234]) AS c1
    ) AS t1
  ) AS t2
) AS the_array;

Đầu tiên, chúng tôi tạo một tập hợp từ mảng, sau đó chúng tôi chỉ chọn các mục nhập riêng biệt và sau đó tổng hợp lại thành mảng.


9
Hoặc "nội tuyến nhiều hơn" ;-) SELECT array_agg(DISTINCT c1) FROM unnest(ARRAY[1234,5343,6353,1234,1234]) t(c1)
Peter Krauss

4

Trong một truy vấn duy nhất, tôi đã làm điều này:

SELECT (select array_agg(distinct val) from ( select unnest(:array_column) as val ) as u ) FROM :your_table;


3

Đối với những người như tôi, những người vẫn phải xử lý postgres 8.2, hàm đệ quy này có thể loại bỏ các bản sao mà không làm thay đổi cách sắp xếp của mảng

CREATE OR REPLACE FUNCTION my_array_uniq(bigint[])
  RETURNS bigint[] AS
$BODY$
DECLARE
    n integer;
BEGIN

    -- number of elements in the array
    n = replace(split_part(array_dims($1),':',2),']','')::int;

    IF n > 1 THEN
        -- test if the last item belongs to the rest of the array
        IF ($1)[1:n-1] @> ($1)[n:n] THEN
            -- returns the result of the same function on the rest of the array
            return my_array_uniq($1[1:n-1]);
        ELSE
            -- returns the result of the same function on the rest of the array plus the last element               
            return my_array_uniq($1[1:n-1]) || $1[n:n];
        END IF;
    ELSE
        -- if array has only one item, returns the array
        return $1;
    END IF;
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE;

ví dụ như :

select my_array_uniq(array[3,3,8,2,6,6,2,3,4,1,1,6,2,2,3,99]);

sẽ cho

{3,8,2,6,4,1,99}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.