【问题标题】:Alphanumeric case in-sensitive sorting in postgrespostgres中不区分大小写的字母数字排序
【发布时间】:2013-03-15 08:13:20
【问题描述】:

我是 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 中对此有任何解决方案,请提出建议。

【问题讨论】:

  • 我正在添加一个平面:“区分大小写的排序(在 postgres 中是默认设置)”,这并不完全正确。 default 表示“表示为数据库定义的区域设置”。 (参考:PostgreSQL 文档 collat​​ion.html)。示例:在 Windows 上,它可能不区分大小写。我在 Windows 10 上就是这样。

标签: postgresql postgresql-9.1


【解决方案1】:

我的 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_1name_2,然后:

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

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

【讨论】:

  • 谢谢米哈尔。我检查了 psql -l 但没有显示配置的语言环境。在 SELECT 中使用 COLLATE "pl_PL" 可以工作并在不区分大小写的情况下对列表进行排序,但是字母数字的问题仍然存在,并且 "a2" 列在 "a11" 和 "a19" 之后。您的意思是使用适当的 COLLATE 将解决字母数字排序问题?
  • 仅供参考,'a2''a11' 之前称为自然排序,SQLite 对此有贡献:参见sqlite.org/forum/info/65814bc11d873327
【解决方案2】:

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

select name
from testsorting
order by
    upper(left(name, 1)),
    (substring(name from 2) || '0')::integer

【讨论】:

  • 我收到错误:invalid input syntax for integer: "" with this。我需要检查整理吗?如果我最后删除 ::integer,我得到的输出没有完全排序。 a11 和 a19 在 a2 之前列出,这是错误的 (A, a , a1,a11,a19,a2, a20, B, b)。正确的排序顺序应该是 A、a、a1、a2、a11、a19、a20、B、b。
  • 感谢 Clodoaldo。由于 null 值,我收到了这个错误,因此需要额外的开销来按照您建议的方法处理 null 值。有cmets吗?
  • @Akhilesh 空值不会产生该错误消息。检查 select (substring(null from 2) || '0')::integer.确切的错误信息是什么?
  • 啊终于找到我想要的了。
【解决方案3】:

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

image attached for collation results with ubuntu 15.04 as host OS

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

      CREATE INDEX testsorting_name on testsorting(upper(left(name,1)), substring(name from 2)::integer)
      

      【讨论】:

      • 这是索引,不是排序依据。它不会对您的列表进行排序,Clodoaldo Neto 的回答会。这将使排序更有效率。
      • 这个索引可能不会用于排序。据我在 9.3 中看到的,只有一个唯一索引用于排序。不过,我很乐意被证明是错误的......
      • 任何 B 树索引都可以用于排序,无论它是否唯一:postgresql.org/docs/9.3/static/indexes-ordering.html。显然取决于反映正在执行的特定查询的现有索引。
      【解决方案6】:

      答案的灵感来自this one
      通过使用一个函数,如果您在不同的查询中需要它,它会更容易保持干净。

      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)
      

      【讨论】:

        猜你喜欢
        • 2011-07-25
        • 2011-08-14
        • 2022-01-25
        • 2023-03-17
        • 1970-01-01
        • 2020-03-20
        • 1970-01-01
        • 2012-09-20
        • 2020-08-24
        相关资源
        最近更新 更多