Postgresql排序混合的字母数字数据

时间:2011-08-10 22:21:31

标签: postgresql sorting alphanumeric

运行此查询:

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

这里有什么问题?

7 个答案:

答案 0 :(得分:18)

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

SELECT name
FROM folders
ORDER BY name::bytea;

结果:

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

答案 1 :(得分:5)

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

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

这将对列文本进行排序,首先是所有字符,可选地排除结尾空格后跟数字,然后排除这些可选数字。

在我的测试中表现良好。

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

答案 2 :(得分:4)

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

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 :(得分:2)

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。

答案 4 :(得分:2)

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 DB中,当我使用按名称查询简单订单时,“名称”列包含以下内容:

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

查询结果,修改后:

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

答案 5 :(得分:0)

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;

答案 6 :(得分:0)

上面的一个Vlk的回答对我有很大的帮助,但它只按数字部分排序,在我的情况下排在第二位。我的数据就像(桌子1,桌子2,桌子3 ......)一个字符串部分,一个空格和一个数字部分。 A Vlk的答案中的语法返回按数字排序的数据,并且这是上面唯一的答案。但是当字符串部分不同时(例如桌面3,桌面4,桌子1,桌面5 ...)表1将从桌面2获得第一个。我使用下面的语法修复了这个:

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