PostgreSQL在订购时忽略破折号

时间:2011-02-10 09:37:39

标签: postgresql encoding utf-8 latin1

我有一个使用da_DK.utf8语言环境创建的PostgreSQL 8.4数据库。

dbname=> show lc_collate;
 lc_collate
------------
 da_DK.utf8
(1 row)

当我从一个表格中选择一个我在一个字符变化列上订购的东西时,我得到一个奇怪的行为IMO。在排序结果时,PostgreSQL会忽略前缀值的破折号,例如:

 select name from mytable order by name asc;

可能会返回类似

的内容
 name
 ----------------
 Ad...
 Ae...
 Ag...
 - Ak....
 At....

短划线前缀似乎被忽略了。

我可以通过在订购时将列转换为latin1来解决此问题:

 select name from mytable order by convert_to(name, 'latin1') asc;

我得到了预期的结果:

 name
 ----------------
 - Ak....
 Ad...
 Ae...
 Ag...
 At....

为什么默认情况下会忽略短划线前缀?可以改变这种行为吗?

3 个答案:

答案 0 :(得分:3)

这是因为da_DK.utf8语言环境以这种方式定义它。 Linux语言环境感知实用程序,例如sort也可以这样工作。

如果convert_to(name, 'latin1')找到的字符不是拉丁语1字符集,例如,那么order by convert_to(name, 'SQL_ASCII')会中断,所以这不是一个好的解决方法。

您可以使用order by ( ascii(name) between ascii('a') and ascii('z') or ascii(name) between ascii('A') and ascii('Z') or ascii(name)>127 ), name; ,它将忽略区域设置定义的排序,只使用字节值。


丑陋的黑客编辑:

{{1}}

这将首先排序以ASCII非字母开头的任何内容。这非常难看,因为在字符串中进一步排序会表现得很奇怪,但它对你来说已经足够了。

答案 1 :(得分:1)

在我的特定情况下可以使用的解决方法是用感叹号替换破折号。我碰巧知道我永远不会得到感叹号,它会在任何字母或数字之前排序。

select name from mytable order by translate(name, '-', '!') asc

它肯定会影响性能,所以我可能会考虑创建一个专门的排序列,但我真的不喜欢它......

答案 2 :(得分:0)

我不知道荷兰语的排序规则怎么样,但是对于波兰语中的特殊字符,如空格,短划线等,在大多数词典的排序中都没有“计算”。一些好的排序例程也会这样做并忽略这些特殊字符。可能在荷兰语中有类似的规则,这个规则是由Ubuntu语言环境感知排序函数实现的。