【问题标题】:Postgresql sorting mixed alphanumeric dataPostgresql 对混合字母数字数据进行排序
【发布时间】:2011-08-10 22:21:31
【问题描述】:

运行此查询:

select name from folders order by name

返回这些结果:

alphanumeric
a test
test 20
test 19
test 1
test 10

但我期待:

a test
alphanumeric
test 1
test 10
test 19
test 20

这里有什么问题?

【问题讨论】:

  • 看起来很奇怪:'test 20' < 'test 19'。通过检查 SHOW lc_collate; 你有什么 LC_COLLATE ?我有en_US.UTF-8,它使用ORDER BY name ASC 返回完全想要的输出。
  • 我也得到了同样的结果。我刚刚做了select 'alphanumeric' < 'a test' 并得到了f
  • 为了记录,我发布了一个答案,指向您手动输入进行整理。它被认为不够可爱,所以我删除了它。但我认为你应该从那里开始。
  • @andrew cooke:我没有投反对票,这很好,排序规则负责排序,但是仅支持 每列排序规则,这在此处可能很有用从 Postgres 9.1 开始。
  • 您好,感谢您的 cmets... SHOW lc_collat​​e;正在返回 es_SV.UTF-8(我住在萨尔瓦多)

标签: postgresql sorting alphanumeric


【解决方案1】:

您可以简单地将 name 列转换为 bytea 数据类型,从而允许与排序无关的排序:

SELECT name
FROM folders
ORDER BY name::bytea;

结果:

     name     
--------------
 a test
 alphanumeric
 test 1
 test 10
 test 19
 test 20
(6 rows)

【讨论】:

  • 大师!这个答案绝对是我过去 2 小时一直在寻找的答案!来自Mysql,当没有数字时将varchars转换为整数时不会出错......
  • 这修复了TRIM 无法解决的前导空格排序问题。
  • 小心,因为它仍然是字母数字(意思是“3”将出现在“20”之后)
【解决方案2】:

所有这些方法都按字母顺序对我的选择进行了排序:

test 1
test 10
test 2
test 20

这个解决方案对我有用(lc_collat​​e: 'ru_RU.UTF8'):

SELECT name
FROM folders
ORDER BY SUBSTRING(name FROM '([0-9]+)')::BIGINT ASC, name;

test 1
test 2
test 10
test 20

【讨论】:

    【解决方案3】:
    select * from "public"."directory" where "directoryId" = 17888 order by
    COALESCE(SUBSTRING("name" FROM '^(\d+)')::INTEGER, 99999999),
    SUBSTRING("name" FROM '[a-zA-z_-]+'),
    COALESCE(SUBSTRING("name" FROM '(\d+)$')::INTEGER, 0),
    "name";
    

    注意:根据需要转义正则表达式,在某些语言中,您必须再添加一个“\”。

    在我的 Postgres 数据库中,当我使用简单的按名称排序查询时,名称列包含以下内容:

    • 1
    • 10
    • 2
    • 21
    • 一个
    • A1
    • A11
    • A5
    • B
    • B2
    • B22
    • B3
    • M 1
    • M 11
    • M 2

    查询结果,修改后:

    • 1
    • 2
    • 10
    • 21
    • 一个
    • A1
    • A5
    • A11
    • B
    • B2
    • B3
    • B22
    • M 1
    • M 2
    • M 11

    【讨论】:

    • 这是一个很好的答案
    • 嗨,Deepak,如何在 sqlite/websql 中复制它?
    • 这是我们系统的绝佳解决方案。干得好迪帕克
    【解决方案4】:

    如果有尾随数字,您可以通过拆分文本手动排序,如下所示:

    SELECT * FROM sort_test
    ORDER BY SUBSTRING(text FROM '^(.*?)( \\d+)?$'),
             COALESCE(SUBSTRING(text FROM ' (\\d+)$')::INTEGER, 0);
    

    这将按列文本排序,首先按所有字符(可选地不包括结尾空格,后跟数字)排序,然后按这些可选数字。

    在我的测试中运行良好。

    更新通过简单的合并(duh)修复了仅字符串排序。

    【讨论】:

    • 为什么投反对票?它有效,并解决了这种情况。这不是最佳 解决方案,但它不涉及更改数据库结构。如果您觉得需要投反对票,请至少发表评论。
    • -1 表示无法解决真正问题的奇怪的 kluge。 (带有多个空格和/或数字的字符串呢?)请参阅上面关于排序规则的 cmets。
    • 我不会说这是一个奇怪的组合。它增加了对尾随数字进行数字排序的能力,而不需要特定版本的 PG。它很好地处理 尾随 数字,因此适用于按顺序编号的文件夹。它处理多个空格,因为它只是检查以确保在尾随数字之前至少有一个空格。如果你尝试过,你会发现它有效,而不是假设。
    • 不适用于诸如“H1C11”之类的文本,因为它为第一个数字排序,而不是尾数
    【解决方案5】:

    OverZealous 回答对我有帮助,但如果数据库中的字符串以数字开头,后跟其他字符,则不起作用。

    以下内容对我有用:

    SELECT name
    FROM folders
    ORDER BY
    COALESCE(SUBSTRING(name FROM '^(\\d+)')::INTEGER, 99999999),
    SUBSTRING(name FROM '^\\d* *(.*?)( \\d+)?$'),
    COALESCE(SUBSTRING(name FROM ' (\\d+)$')::INTEGER, 0),
    name;
    

    所以这个:

    1. 提取字符串中的第一个数字,或使用 99999999。
    2. 提取可能的第一个数字后面的字符串。
    3. 提取尾随数字,或使用 0。

    【讨论】:

      【解决方案6】:

      上面 Vlk 的回答对我帮助很大,但它仅按数字部分对项目进行排序,在我的情况下排在第二位。我的数据就像(办公桌 1、办公桌 2、办公桌 3 ...)一个字符串部分、一个空格和一个数字部分。 A Vlk 的答案中的语法返回了按数字排序的数据,这是上面唯一的答案。但是,当字符串部分不同时(例如,3 号桌、4 号桌、1 号桌、5 号桌...),1 号桌将首先从 2 号桌开始。我使用以下语法解决了这个问题:

          ...order by SUBSTRING(name,'\\w+'), SUBSTRINGname FROM '([0-9]+)')::BIGINT ASC;
      

      【讨论】:

        【解决方案7】:

        Tor 的最后一条 SQL 对我有用。但是,如果您从 php 调用此代码,则需要添加额外的斜杠。

        SELECT name
        FROM folders
        ORDER BY
        COALESCE(SUBSTRING(name FROM '^(\\\\d+)')::INTEGER, 99999999),
        SUBSTRING(name FROM '^\\\\d* *(.*?)( \\\\d+)?$'),
        COALESCE(SUBSTRING(name FROM ' (\\\\d+)$')::INTEGER, 0),
        name;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-10
          • 1970-01-01
          相关资源
          最近更新 更多