【发布时间】:2010-10-22 06:54:34
【问题描述】:
我有一个bigint 类型的数组,如何删除该数组中的重复值?
例如:array[1234, 5343, 6353, 1234, 1234]
我应该得到array[1234, 5343, 6353, ...]
我在 postgres 手册中测试了示例 SELECT uniq(sort('{1,2,3,2,1}'::int[])),但它不起作用。
【问题讨论】:
标签: postgresql
我有一个bigint 类型的数组,如何删除该数组中的重复值?
例如:array[1234, 5343, 6353, 1234, 1234]
我应该得到array[1234, 5343, 6353, ...]
我在 postgres 手册中测试了示例 SELECT uniq(sort('{1,2,3,2,1}'::int[])),但它不起作用。
【问题讨论】:
标签: postgresql
我也面临同样的情况。但在我的例子中,一个数组是通过array_agg 函数创建的。幸运的是,它允许聚合 DISTINCT 值,例如:
array_agg(DISTINCT value)
这对我有用。
【讨论】:
trim(string_agg(distinct to_char(z.dat_codigo,'0000000000'),'')) as dat_codigo,
sort(int[]) and uniq(int[]) functions 由 intarray contrib 模块提供。
要启用它,您必须install the module。
如果您不想使用 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_X 实用程序的标准库 (?)在哪里??
尝试搜索...看到一些但没有标准:
JDBurnZ/postgresql-anyarray,很好的主动性,但需要一些合作来加强。
wiki.postgresql.org/Snippets,受挫的倡议,但“官方 wiki”,需要一些合作来增强。
MADlib:好! .... 但它是一头大象,而不是“纯 SQL sn-ps 库”。
array_distinct()sn-p-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;
【讨论】:
使用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;
【讨论】:
我已经组装了一组存储过程(函数)来解决 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;
首先我们从数组中创建一个集合,然后我们只选择不同的条目,然后将其聚合回数组中。
【讨论】:
SELECT array_agg(DISTINCT c1) FROM unnest(ARRAY[1234,5343,6353,1234,1234]) t(c1)
在一个查询中我这样做了:
SELECT (select array_agg(distinct val) from ( select unnest(:array_column) as val ) as u ) FROM :your_table;
【讨论】:
对于像我这样仍然要处理 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}
【讨论】: