消除后区中重复的数组值

我有一个类型为 bigint的数组,如何删除该数组中的重复值?

Ex: array[1234, 5343, 6353, 1234, 1234]

我应该去拿 array[1234, 5343, 6353, ...]

我在 postgres 手册中测试了示例 SELECT uniq(sort('{1,2,3,2,1}'::int[])),但是它不起作用。

102957 次浏览

ABC0和 uniq(int[])功能intarray贡献模块提供。

要启用它的使用,必须使用 安装模块

If you don't want to use the intarray contrib module, or if you have to remove duplicates from arrays of different type, you have two other ways.

如果您至少有 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)

对于像我这样仍然需要处理 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}

我已经组装了一组存储过程(函数)来解决 PostgreSQL 缺乏数组处理的问题,这个问题被称为 anyarray。这些函数被设计用于处理任何数组数据类型,而不是像 intarray 那样只处理整数: https://www.github.com/JDBurnZ/anyarray

In your case, all you'd really need is anyarray_uniq.sql. Copy & paste the contents of that file into a PostgreSQL query and execute it to add the function. If you need array sorting as well, also add anyarray_sort.sql.

从那里,您可以执行如下简单的查询:

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

返回类似于: ARRAY[1234, 6353, 5343]的内容

Or if you require sorting:

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

Return exactly: 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;

首先,我们从数组中创建一个集合,然后只选择不同的条目,然后将其聚合回数组中。

... 标准图书馆在哪里(?)为这种 Array _ X 实用程序? ? ?

尝试搜索... 看到一些但没有标准:


最简单快速的 array_distinct()代码片段库函数

这里是 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;

我也面对过同样的问题。但在我的例子中,数组是通过 array_agg函数创建的。幸运的是,它可以聚合 很明显值,比如:

  array_agg(DISTINCT value)

这对我有用。

使用 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;

在一个简单的查询中,我这样做了:

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