устранить повторяющиеся значения массива в postgres - PullRequest
63 голосов
/ 22 октября 2010

У меня есть массив типа bigint, как я могу удалить дублирующиеся значения в этом массиве?

Пример: array[1234, 5343, 6353, 1234, 1234]

Я должен получить array[1234, 5343, 6353, ...]

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

Ответы [ 8 ]

67 голосов
/ 22 октября 2010

Функции sort(int[]) и uniq(int[]) предоставляются модулем внутренней поддержки.

Чтобы включить его, вы должны зарегистрировать модуль, выполнив файл _int.sql, который вы можете найти в каталоге contrib вашей установки postgresql.

В системе Debian / Ubuntu вы должны установить пакет postgresql-contrib-8.4, тогда файл будет находиться в /usr/share/postgresql/8.4/contrib/_int.sql (номера версий могут отличаться)

Если вы не хотите использовать модуль вклада intarray или если вам необходимо удалить дубликаты из массивов другого типа, у вас есть два других способа.

Если у вас есть хотя бы 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)
59 голосов
/ 02 июня 2016

Я сталкивался с тем же. Но массив в моем случае создается с помощью функции array_agg. И, к счастью, он позволяет агрегировать DISTINCT значений, например:

  array_agg(DISTINCT value)

Это работает для меня.

14 голосов
/ 19 апреля 2016

... Где statandard библиотеки (?) Для этого вида array_X утилита ??

Попробуйте поискать ... См. Некоторые, но не стандартные:


Самый простой и быстрый 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;
13 голосов
/ 17 мая 2013

Я собрал набор хранимых процедур (функций) для борьбы с отсутствием обработки массивов в PostgreSQL anyarray. Эти функции предназначены для работы с любым типом данных массива, а не только с целыми числами, как это делает intarray:

В вашем случае все, что вам действительно нужно, это 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]

7 голосов
/ 14 мая 2014

Вот «встроенный» способ:

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;

Сначала мы создаем набор из массива, затем выбираем только отдельные записи, а затем собираем его обратно в массив.

5 голосов
/ 22 февраля 2017

Использование 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;
2 голосов
/ 12 января 2013

Для таких людей, как я, которым все еще приходится иметь дело с 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}
0 голосов
/ 23 апреля 2019

Один из возможных вариантов

UPDATE table SET array_column = uniq(array_column)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...