【问题标题】:Sorting array elements排序数组元素
【发布时间】:2022-03-16 16:54:02
【问题描述】:

我想编写一个存储过程,它获取一个数组作为输入参数,然后对该数组进行排序并返回排序后的数组。

请帮忙。

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    毫无疑问,对整数数组进行排序的最佳方法是使用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 将取消嵌套数组的所有级别:因此,如果您尝试对数组数组进行排序,那么您将得到意想不到的结果:数组的形状保持不变,但值是单独排序的,而不是作为子数组。
    • 您好,bigint 没有类似的扩展?
    【解决方案2】:

    在 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 函数。
    【解决方案3】:

    只需使用函数 unnest():

    SELECT 
        unnest(ARRAY[1,2]) AS x
    ORDER BY 
        x DESC;
    

    请参阅 Pg 文档中的 array functions

    【讨论】:

      【解决方案4】:

      这对我有用 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 的了解要多得多,并且有更好的答案。如果可能的话,也投票删除我的答案。

      【讨论】:

      • 我用一些更现代的技术更新了那篇 wiki 文章,所以请使用文章中的代码(或查看我的答案),而不是此处显示的旧代码。
      【解决方案5】:

      很好地展示了 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
      );
      $$;
      

      【讨论】:

      • @MartijnPieters 请注意它的答案与我的相同,但我在一年前回答并引用了我从哪里得到的。
      • @AdamGent:我想我在第一个答案队列中找到了这个,只是重新格式化了 SQL 以使其可读。换句话说,除了不可读的格式之外,我没有任何上下文。
      【解决方案6】:

      如果您正在寻找适用于任何数据类型的解决方案,我建议您采用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
      

      【讨论】:

      • 比较长,但是比克雷格的解决方案好吗?
      • 我不确定我是否理解您的问题的缩进。您的实施是否“更好”由您决定。
      • 好吧,Craig 提供了一个 5 行工作解决方案。大约一年后,您添加了一个更长解决方案的答案。所以我想你的解决方案一定会更好,或者在其他情况下不能工作。我是(Postgre)SQL新手,所以我无法判断,所以我问。 :)
      • 我没有进行压力测试来比较我列出的方法与 Craig 的方法。如果有机会,我可能会这样做。 :) 我确实补充说,也可以执行排序,而无需创建可能对某些人有用的存储过程。
      • 对,当然我指的是存储过程。不一定在压力测试方面,但可能在“设计”或其他方面。但如果你不知道,没问题,这只是另一种解决方案,也许其他人稍后会来评论一个或另一个。 ;)
      【解决方案7】:

      我很惊讶没有人提到收容操作员:

      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,如果所有元素都是唯一的,则它们必须相同)

      【讨论】:

        猜你喜欢
        • 2022-06-22
        • 1970-01-01
        • 2019-09-01
        • 1970-01-01
        • 2020-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多