29

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

10_asdaasda
100_inkskabsjd
11_kancaascjas
45_aksndsialcn
22_dsdaskjca
100_skdnascbka

我希望它们基本上按字符串前面的数字排序,然后按字符串名称本身排序,但是当然,字符会被一一比较,因此按名称排序的结果会产生:

10_asdaasda
100_inkskabsjd
100_skdnascbka
11_kancaascjas
22_dsdaskjca
45_aksndsialcn

而不是我更喜欢的顺序:

10_asdaasda
11_kancaascjas
22_dsdaskjca
45_aksndsialcn
100_inkskabsjd
100_skdnascbka

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

4

4 回答 4

44

理想的方法是标准化您的设计并将列的两个组件拆分为两个单独的列。一种类型integer,一种text

使用当前表,您可以:

SELECT col
FROM   tbl
ORDER  BY (substring(col, '^[0-9]+'))::int  -- cast to integer
         , substring(col, '[^0-9_].*$');    -- works as text

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

这些正则表达式有些容错:
第一个正则表达式从左边挑选最长的数字字符串,NULL如果没有找到数字,那么转换integer不会出错。
第二个正则表达式从不是数字或“_”的第一个字符中挑选字符串的其余部分。

如果下划线 ( _) 是明确的分隔符,split_part()则速度更快:

SELECT col
FROM   tbl
ORDER  BY split_part(col, '_', 1)::int
        , split_part(col, '_', 2);

db<>在这里摆弄

看:

于 2012-07-10T16:58:46.120 回答
9

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

   order by substring(column, '^[0-9]+')::int, substring(column, '[^0-9]*$')
于 2013-06-21T18:33:40.943 回答
4

有一种方法可以在表达式上使用索引。这不是我首选的解决方案(我会选择 Brad 的),但您可以在以下表达式上创建索引(有更多方法可以做到):

CREATE INDEX idx_name ON table (CAST(SPLIT_PART(columname, '_', 1) AS integer));  

然后你可以在CAST(SPLIT_PART(columname, '_', 1) AS integer)每次需要下划线字符前的数字时进行搜索和排序,例如:

SELECT * FROM table ORDER BY CAST(SPLIT_PART(columname, '_', 1) AS integer);  

您可以通过在 上创建索引来对字符串部分执行相同的操作SPLIT_PART(columname, '_', 2),然后也进行相应的排序。
然而,正如我所说,我发现这个解决方案非常难看。我肯定会使用另外两列(一列用于数字,一列用于字符串),然后甚至可能删除您在此处提到的列。

于 2012-07-10T17:03:31.760 回答
1

您应该向具有数字数据类型的数据库添加一个新列,并在持久化新记录时将其设置为与您拥有的字符串值的前缀相同的值。

然后,您可以在正确键入的数字列上创建索引以进行排序。

于 2012-07-10T16:53:26.513 回答