UFO ET IT

postgres에서 중복 배열 값 제거

ufoet 2020. 11. 9. 21:39
반응형

postgres에서 중복 배열 값 제거


유형의 배열이 bigint있습니다. 해당 배열에서 중복 값을 제거하려면 어떻게해야합니까?

전의: array[1234, 5343, 6353, 1234, 1234]

나는 얻어야한다 array[1234, 5343, 6353, ...]

SELECT uniq(sort('{1,2,3,2,1}'::int[]))postgres 매뉴얼에서 예제 테스트 했지만 작동하지 않습니다.


sort(int[])uniq(int[])기능은 intarray의 contrib 모듈에 의해 제공된다.

이를 사용하려면 postgresql 설치의 contrib 디렉토리에있는 _int.sql 파일을 실행하여 모듈을 등록해야합니다.

Debian / Ubuntu 시스템에서는 postgresql-contrib-8.4 패키지를 설치해야합니다. 그러면 파일은 /usr/share/postgresql/8.4/contrib/_int.sql에 있습니다 (버전 번호는 다를 수 있음).

intarray contrib 모듈을 사용하지 않거나 다른 유형의 배열에서 중복을 제거해야하는 경우 두 가지 다른 방법이 있습니다.

PostgreSQL 8.4 이상이 있으면 unnest(anyarray)기능 을 활용할 수 있습니다.

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

또는이 작업을 수행하는 자체 함수를 만들 수 있습니다.

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$;

다음은 샘플 호출입니다.

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

나는 똑같이 직면했다. 하지만 제 경우에는 배열이 array_agg함수 를 통해 생성됩니다 . 다행히 다음 과 같이 DISTINCT을 집계 할 수 있습니다 .

  array_agg(DISTINCT value)

이것은 나를 위해 작동합니다.


... 이런 종류의 array_X 유틸리티를 위한 statandard 라이브러리 (?)는 어디에 있습니까 ?

검색해보십시오 ... 표준은 아니지만 일부보기 :


가장 간단하고 빠른 array_distinct()snippet-lib 함수

여기에 array_unique()or에 대한 가장 간단하고 빠른 구현이 있습니다 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;

참고 : 배열 배열을 제외하고 모든 데이터 유형에서 예상대로 작동합니다.

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}"

"부작용"은 요소 집합의 모든 배열을 분해하는 것입니다.

추신 : JSONB 배열을 사용하면 잘 작동합니다.

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

편집 : 더 복잡하지만 유용한 "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;

PostgreSQL의 배열 처리 부족에 맞서기 위해 일련의 저장 프로 시저 (함수)를 모았습니다 anyarray. 이 함수는 intarray처럼 정수뿐만 아니라 모든 배열 데이터 유형에서 작동하도록 설계되었습니다 : https://www.github.com/JDBurnZ/anyarray

귀하의 경우 정말 필요한 것은 anyarray_uniq.sql. 해당 파일의 내용을 PostgreSQL 쿼리에 복사하여 붙여넣고 실행하여 함수를 추가합니다. 배열 정렬도 필요하면 anyarray_sort.sql.

여기에서 다음과 같이 간단한 쿼리를 수행 할 수 있습니다.

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

다음과 유사한 것을 반환합니다. ARRAY[1234, 6353, 5343]

또는 정렬이 필요한 경우 :

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

정확히 반환 : ARRAY[1234, 5343, 6353]


다음은 "인라인"방식입니다.

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;

먼저 배열에서 집합을 만든 다음 고유 항목 만 선택한 다음 다시 배열로 집계합니다.


Using DISTINCT implicitly sorts the array. If the relative order of the array elements needs to be preserved while removing duplicates, the function can be designed like the following: (should work from 9.4 onwards)

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;

For people like me who still have to deal with postgres 8.2, this recursive function can eliminate duplicates without altering the sorting of the array

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;

for exemple :

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

will give

{3,8,2,6,4,1,99}

One of possible variant

UPDATE table SET array_column = uniq(array_column)

참고URL : https://stackoverflow.com/questions/3994556/eliminate-duplicate-array-values-in-postgres

반응형