23

我是 postrges 的新手,想对 varchar 类型的列进行排序。想用下面的例子来解释这个问题:

表名:testsorting

   order       name
    1            b
    2            B
    3            a
    4            a1
    5            a11
    6            a2
    7            a20
    8            A
    9            a19

区分大小写的排序(在 postgres 中是默认的)给出:

select name from testsorting order by name;

    A
    B
    a
    a1
    a11
    a19
    a2
    a20
    b

不区分大小写的排序给出:

按 UPPER(name) 从测试排序顺序中选择名称;

      A
      a
      a1
      a11
      a19
      a2
      a20
      B
      b

如何在 postgres 中进行字母数字大小写不敏感排序以获得以下顺序

          a
          A
          a1
          a2
          a11
          a19
          a20
          b
          B

我不介意大写或小写字母的顺序,但顺序应该是“aAbB”或“AaBb”,而不应该是“ABab”

如果您在 postgres 中对此有任何解决方案,请提出建议。

4

6 回答 6

10

我的 PostgreSQL 按你想要的方式排序。PostgreSQL 比较字符串的方式是由语言环境和排序规则决定的。当您使用创建数据库时createdb,可以-l选择设置语言环境。您还可以使用以下命令检查它在您的环境中的配置方式psql -l

[postgres@test]$ psql -l
List of databases
 Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges
---------+----------+----------+------------+------------+-----------------------
 mn_test | postgres | UTF8     | pl_PL.UTF8 | pl_PL.UTF8 |

如您所见,我的数据库使用波兰排序规则。

如果您使用其他排序规则创建数据库,那么您可以在查询中使用其他排序规则,就像:

SELECT * FROM sort_test ORDER BY name COLLATE "C";
SELECT * FROM sort_test ORDER BY name COLLATE "default";
SELECT * FROM sort_test ORDER BY name COLLATE "pl_PL";

您可以通过以下方式列出可用的排序规则:

SELECT * FROM pg_collation;

编辑:

哦,我错过了'a11'必须在'a2'之前。

我不认为标准排序规则可以解决字母数字排序。对于这种排序,您必须像在 Clodoaldo Neto 响应中一样将字符串拆分为多个部分。如果您经常必须以这种方式订购,另一个有用的选项是将名称字段分成两列。您可以在 INSERT 和 UPDATE 上创建触发器,该触发器name分为name_1然后name_2

SELECT name FROM sort_test ORDER BY name_1 COLLATE "en_EN", name_2;

(我将排序规则从波兰语更改为英语,您应该使用您的母语排序规则对 aącć 等字母进行排序)

于 2013-03-15T09:16:31.720 回答
5

如果名称始终采用以下1 alpha followed by n numerics格式,则:

select name
from testsorting
order by
    upper(left(name, 1)),
    (substring(name from 2) || '0')::integer
于 2013-03-15T11:24:20.053 回答
2

PostgreSQL 使用 C 库语言环境工具对字符串进行排序。C 库由主机操作系统提供。在 Mac OS X 或 BSD 系列操作系统上,UTF-8 语言环境定义被破坏,因此结果按照排序规则“C”。

附上以 ubuntu 15.04 作为主机操作系统的整理结果的图像

查看 postgres wiki 上的常见问题解答以获取更多详细信息:https ://wiki.postgresql.org/wiki/FAQ

于 2016-05-26T10:36:56.877 回答
1

就我而言,我使用了 PostgreSQL 模块citext并使用数据类型CITEXT而不是TEXT. 它使这些列的排序和搜索不区分大小写。

该模块可以使用 SQL 命令安装CREATE EXTENSION IF NOT EXISTS citext;

于 2019-11-06T09:13:22.153 回答
0

我同意 Clodoaldo Neto 的回答,但也不要忘记添加索引

CREATE INDEX testsorting_name on testsorting(upper(left(name,1)), substring(name from 2)::integer)
于 2013-03-17T05:45:28.857 回答
0

答案深受此启发。
通过使用一个函数,如果您在不同的查询中需要它,它会更容易保持清洁。

CREATE OR REPLACE FUNCTION alphanum(str anyelement)
   RETURNS anyelement AS $$
BEGIN
   RETURN (SUBSTRING(str, '^[^0-9]*'),
      COALESCE(SUBSTRING(str, '[0-9]+')::INT, -1) + 2000000);
END;
$$ LANGUAGE plpgsql IMMUTABLE;

然后你可以这样使用它:

SELECT name FROM testsorting ORDER BY alphanum(name);

测试:

WITH x(name) AS (VALUES ('b'), ('B'), ('a'), ('a1'),
   ('a11'), ('a2'), ('a20'), ('A'), ('a19'))
SELECT name, alphanum(name) FROM x ORDER BY alphanum(name);

 name |  alphanum   
------+-------------
 a    | (a,1999999)
 A    | (A,1999999)
 a1   | (a,2000001)
 a2   | (a,2000002)
 a11  | (a,2000011)
 a19  | (a,2000019)
 a20  | (a,2000020)
 b    | (b,1999999)
 B    | (B,1999999)
于 2016-07-06T22:48:55.473 回答