使用PostgreSQL进行字母数字排序

use*_*055 24 sql sorting postgresql natural-sort sql-order-by

在数据库中,我有以下格式的各种字母数字字符串:

10_asdaasda
100_inkskabsjd
11_kancaascjas
45_aksndsialcn
22_dsdaskjca
100_skdnascbka
Run Code Online (Sandbox Code Playgroud)

我希望它们基本上按字符串前面的数字排序,然后按字符串名称本身排序,但当然,字符会逐个进行比较,因此Order by name的结果会产生:

10_asdaasda
100_inkskabsjd
100_skdnascbka
11_kancaascjas
22_dsdaskjca
45_aksndsialcn
Run Code Online (Sandbox Code Playgroud)

而不是我更喜欢的顺序:

10_asdaasda
11_kancaascjas
22_dsdaskjca
45_aksndsialcn
100_inkskabsjd
100_skdnascbka
Run Code Online (Sandbox Code Playgroud)

老实说,如果字符串只按前面的数字排序,我会没事的.我对PostgreSQL不太熟悉,所以我不确定最好的方法是什么.我很感激任何帮助!

Erw*_*ter 36

理想的方法是规范化数据并将列的两个组件拆分为两个单独的列.其中一种integer,一种text.

使用当前表,您可以执行以下演示:

WITH x(t) AS (
    VALUES
     ('10_asdaasda')
    ,('100_inkskabsjd')
    ,('11_kancaascjas')
    ,('45_aksndsialcn')
    ,('22_dsdaskjca')
    ,('100_skdnascbka')
    )
SELECT t
FROM   x
ORDER  BY (substring(t, '^[0-9]+'))::int     -- cast to integer
          ,substring(t, '[^0-9_].*$')        -- works as text
Run Code Online (Sandbox Code Playgroud)

可以使用相同的substring()表达式来拆分列.

正则表达式有点容错:

  • 第一个正则表达式从左边选择最长的数字字符串,NULL如果没有找到数字,那么转换为integer不会出错.

  • 第二个正则表达式从第一个不是数字或'_'的字符中选取字符串的其余部分.

如果下划线无论如何都是明确的分隔符,split_part()则更快:

ORDER  BY (split_part(t, '_', 1)::int
          ,split_part(t, '_', 2)
Run Code Online (Sandbox Code Playgroud)

回答你的例子

SELECT name
FROM   nametable
ORDER  BY (split_part(name, '_', 1)::int
          ,split_part(name, '_', 2)
Run Code Online (Sandbox Code Playgroud)


小智 6

您可以将正则表达式与子字符串一起使用

   order by substring(column, '^[0-9]+')::int, substring(column, '[^0-9]*$')
Run Code Online (Sandbox Code Playgroud)