Подтвердить что ты не робот

Исключить повторяющиеся значения массива в postgres

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

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

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

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

4b9b3361

Ответ 1

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

Чтобы включить его, вы должны установить модуль.

Если вы не хотите использовать модуль Contribute 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)

Ответ 2

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

  array_agg(DISTINCT value)

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

Ответ 3

... Где стандартные библиотеки (?) для такого рода утилиты array_X??

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

  • postgres.cz/wiki/Array_based_functions: хорошая ссылка!

  • JDBurnZ/postgresql-anyarray, хорошая инициатива, но для ее улучшения необходимо сотрудничество.

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

  • 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 null"

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;

Ответ 4

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

Ответ 5

Здесь "встроенный" способ:

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;

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

Ответ 6

Использование 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;

Ответ 7

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

Ответ 8

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

UPDATE table SET array_column = uniq(array_column)