【发布时间】:2022-03-16 16:54:02
【问题描述】:
我想编写一个存储过程,它获取一个数组作为输入参数,然后对该数组进行排序并返回排序后的数组。
请帮忙。
【问题讨论】:
标签: postgresql
我想编写一个存储过程,它获取一个数组作为输入参数,然后对该数组进行排序并返回排序后的数组。
请帮忙。
【问题讨论】:
标签: postgresql
毫无疑问,对整数数组进行排序的最佳方法是使用intarray extension,它比任何 SQL 公式都快得多、快得多:
CREATE EXTENSION intarray;
SELECT sort( ARRAY[4,3,2,1] );
适用于任何数组类型的函数是:
CREATE OR REPLACE FUNCTION array_sort (ANYARRAY)
RETURNS ANYARRAY LANGUAGE SQL
AS $$
SELECT ARRAY(SELECT unnest($1) ORDER BY 1)
$$;
(在其他地方讨论后,我已将我的版本替换为 Pavel's slightly faster one)。
【讨论】:
array_sort() 函数应该在第二个$$ 之后使用STABLE(或者可能是IMMUTABLE)标签来定义。其他程序员可能会查看此类波动性标签以获取有关给定函数如何工作的提示。 LANGUAGE SQL-functions(通常)由 Postgres 内联,但无论以哪种方式添加标签都没有害处。
unnest 将取消嵌套数组的所有级别:因此,如果您尝试对数组数组进行排序,那么您将得到意想不到的结果:数组的形状保持不变,但值是单独排序的,而不是作为子数组。
在 PostrgreSQL 8.4 及更高版本中,您可以使用:
select array_agg(x) from (select unnest(ARRAY[1,5,3,7,2]) AS x order by x) as _;
但不会很快。
在较旧的 Postgres 中,您可以像这样实现 unnest
CREATE OR REPLACE FUNCTION unnest(anyarray)
RETURNS SETOF anyelement AS
$BODY$
SELECT $1[i] FROM
generate_series(array_lower($1,1),
array_upper($1,1)) i;
$BODY$
LANGUAGE 'sql' IMMUTABLE
还有这样的array_agg:
CREATE AGGREGATE array_agg (
sfunc = array_append,
basetype = anyelement,
stype = anyarray,
initcond = '{}'
);
但它会更慢。
您还可以在 pl/pgsql 或您可以插入 postgres 的任何其他语言中实现任何排序算法。
【讨论】:
intarray contrib 模块中的sort 函数。
【讨论】:
这对我有用 http://www.pgsql.cz/index.php/PostgreSQL_SQL_Tricks_I#General_array_sort
CREATE OR REPLACE FUNCTION array_sort (ANYARRAY)
RETURNS ANYARRAY LANGUAGE SQL
AS $$
SELECT ARRAY(
SELECT $1[s.i] AS "foo"
FROM
generate_series(array_lower($1,1), array_upper($1,1)) AS s(i)
ORDER BY foo
);
$$;
请参阅 Craig 的答案,因为他对 Postgres 的了解要多得多,并且有更好的答案。如果可能的话,也投票删除我的答案。
【讨论】:
很好地展示了 PostgreSQL 的特性是 David Fetter 的一般排序过程。
CREATE OR REPLACE FUNCTION array_sort (ANYARRAY)
RETURNS ANYARRAY LANGUAGE SQL
AS $$
SELECT ARRAY(
SELECT $1[s.i] AS "foo"
FROM
generate_series(array_lower($1,1), array_upper($1,1)) AS s(i)
ORDER BY foo
);
$$;
【讨论】:
如果您正在寻找适用于任何数据类型的解决方案,我建议您采用YouLikeProgramming.com 中列出的方法。
本质上,您可以创建一个存储过程(下面的代码)来为您执行排序,您所需要做的就是将您的数组传递给该过程以便对其进行适当的排序。
我还包含了一个不需要使用存储过程的实现,如果您希望您的查询更便于传输。
创建存储过程
DROP FUNCTION IF EXISTS array_sort(anyarray);
CREATE FUNCTION
array_sort(
array_vals_to_sort anyarray
)
RETURNS TABLE (
sorted_array anyarray
)
AS $BODY$
BEGIN
RETURN QUERY SELECT
ARRAY_AGG(val) AS sorted_array
FROM
(
SELECT
UNNEST(array_vals_to_sort) AS val
ORDER BY
val
) AS sorted_vals
;
END;
$BODY$
LANGUAGE plpgsql;
对数组值进行排序(适用于任何数组数据类型)
-- The following will return: {1,2,3,4}
SELECT ARRAY_SORT(ARRAY[4,3,2,1]);
-- The following will return: {in,is,it,on,up}
SELECT ARRAY_SORT(ARRAY['up','on','it','is','in']);
不使用存储过程对数组值进行排序
在以下查询中,只需将 ARRAY[4,3,2,1] 替换为您的数组或返回数组的查询:
WITH
sorted_vals AS (
SELECT
UNNEST(ARRAY[4,3,2,1]) AS val
ORDER BY
val
)
SELECT
ARRAY_AGG(val) AS sorted_array
FROM
sorted_vals
...或...
SELECT
ARRAY_AGG(vals.val) AS sorted_arr
FROM (
SELECT
UNNEST(ARRAY[4,3,2,1]) AS val
ORDER BY
val
) AS vals
【讨论】:
我很惊讶没有人提到收容操作员:
select array[1,2,3] <@ array[2,1,3] and array[1,2,3] @> array[2,1,3];
?column?
══════════
t
(1 row)
请注意,这要求数组的所有元素都必须是唯一的。
(如果a包含b,b包含a,如果所有元素都是唯一的,则它们必须相同)
【讨论】: