усунути повторювані значення масиву в postgres


86

У мене є масив типу bigint, як я можу видалити повторювані значення в цьому масиві?

Приклад: array[1234, 5343, 6353, 1234, 1234]

Я повинен отримати array[1234, 5343, 6353, ...]

Я протестував приклад SELECT uniq(sort('{1,2,3,2,1}'::int[]))у посібнику postgres, але він не працює.

Відповіді:


92

Я стикався з тим самим. Але масив у моєму випадку створюється за допомогою array_aggфункції. І, на щастя, це дозволяє агрегувати значення DISTINCT , наприклад:

  array_agg(DISTINCT value)

Це працює для мене.


5
Зверніть увагу, що DISTINCT не підтримується для функцій вікна.
Мислиме

tks guytrim(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]) дає "{{1,2,2,3}}"
user48956

@ user48956, що логічно, коли ви вводите масив як значення, вам потрібно встановити один стовпець як значення, згруповане за запитом
Daniël Tulp

83

sort(int[])І uniq(int[])функції забезпечуються INTArray модулем вно.

Щоб дозволити його використання, потрібно встановити модуль .

Якщо ви не хочете використовувати модуль 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)

1
Рішення проблеми ("усунення повторюваних значень масиву") не потрібно сортувати . Хоча зазвичай це корисна функція, вона не потрібна (вартість процесора) у цьому контексті / вимозі.
Пітер Краус

27

... Де стандартні бібліотеки (?) Для цього виду утиліти array_X ??

Спробуйте здійснити пошук ... Перегляньте деякі, але не стандартні:

  • postgres.cz/wiki/Array_based_functions : гарна довідка!

  • JDBurnZ / postgresql-anyarray , хороша ініціатива, але потребує певної співпраці для вдосконалення.

  • wiki.postgresql.org/Snippets , розчарована ініціатива, але "офіційна wiki", потребує певної співпраці для посилення.

  • MADlib : добре! .... але це слон, а не "чиста бібліотека фрагментів SQL".


Найпростіша та швидша array_distinct()функція snippet-lib

Тут найпростіша і, можливо, швидша реалізація для array_unique()або 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}"

"побічним ефектом" є вибух усіх масивів у наборі елементів.

PS: з масивами 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;

чи можете ви пояснити, що робить t (x) у FROM unnest ($ 1) t (x) ... а також як я можу дотримуватись порядку предметів, у яких вони вставлені
abhirathore2006,

@ abhirathore2006 ця відповідь є Wiki, ви можете написати пояснення, які запропонували. Про "зберігати порядок", ні, це руйнівне рішення. Див. Рішення PLpgSQL на цій сторінці, щоб зберегти вихідний порядок масивів. Це також поєднує два вимоги - сортування та розрізнення (див. Успіх основної відповіді тут та мій коментар там).
Пітер Краус

не турбуйтеся, я вже знайшов рішення звідкись ще, так, це рішення
plsql

13

Я зібрав набір збережених процедур (функцій) для боротьби з відсутністю придуманого 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]


13

Використання DISTINCTнеявно сортує масив. Якщо відносний порядок елементів масиву потрібно зберігати під час видалення дублікатів, функція може бути спроектована таким чином: (повинна працювати з 9.4 і далі)

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
найкраща відповідь! дивіться також: dba.stackexchange.com/questions/211501/…
fjsj

9

Ось "вбудований" спосіб:

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;

Спочатку ми створюємо набір з масиву, потім ми вибираємо лише різні записи, а потім агрегуємо його назад у масив.


9
Або "більш вбудований" ;-) SELECT array_agg(DISTINCT c1) FROM unnest(ARRAY[1234,5343,6353,1234,1234]) t(c1)
Пітер Краус


3

Для таких людей, як я, яким все ще доводиться мати справу з postgres 8.2, ця рекурсивна функція може усунути дублікати, не змінюючи сортування масиву

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;

для прикладу:

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

дам

{3,8,2,6,4,1,99}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.