我有一个Delphi6程序(单字节字符),它使用默认的不区分大小写的AnsiCompareText函数对TStringList中的字符串进行排序,然后调用Windows kernel32.dll中的CompareStringA函数。(区域设置为匈牙利语。)
我想在PostgreSQL数据库中,在Kubuntu(linux-image-3.2.0-65-generic-pae,32位x86,KDE 4.8.5)系统上做同样的排序。它是由
CREATE DATABASE <...>
WITH OWNER = postgres
ENCODING = 'UTF8'
TABLESPACE = pg_default
LC_COLLATE = 'hu_HU.UTF-8'
LC_CTYPE = 'hu_HU.UTF-8'
CONNECTION LIMIT = -1;
如果按C或POSIX排序,则重音字符不会按字母顺序排序。
如果按默认排序规则排序,将忽略空格和某些特殊字符。当这些发生在字符串开头时,这是一个问题。
(指定排序规则很容易,因为PostgreSQL 9.1:请参见http://www.postgresql.org/docs/9.3/static/collation.html)
本主题中提出了几个问题,例如PostgreSQL Sort
答案不能一概而论:它只排除了第一个字符位置的“@”。
我的问题可能是Is there any way to have PostgreSQL not collapse punctuation and spaces when collating using a language?
这里的答案指向PostgreSQL的TODO列表:http://wiki.postgresql.org/wiki/Todo:ICU
从那以后有什么变化吗?
我需要的是一个排序规则,它将空格和特殊字符保留在ASCII位置,并按字母顺序对重音字符进行排序,就像在Windows中一样。
我必须编写一个自定义区域设置(如何)?或者一个定制的比较函数,可能是用Delphi编写的(如何添加到PostgreSQL中)?或者把特殊字符翻译成十六进制,但是它们会被分类到文本中。将所有字符转换为十六进制(并将大小写和重音差异映射到同一代码)似乎很糟糕——这意味着我自己编写完整的排序规则。我相信应该有办法解决这个问题。
最佳答案
除非您可以更改数据库的编码/排序规则以匹配您的Windows系统,否则添加一些自定义比较代码可能是您唯一的选择。
如果ICU的排序顺序(如您链接的question中所述)是您想要的,那么请查看pg_collkey(Postgres ICU包装)。安装了这个程序后,只需将ORDER BY foo
替换为ORDER BY collkey(foo,'hu_HU')
(同样,对于任何显式的>
/<
比较,在这些比较所依赖的任何索引中也是如此)。
如果你想让它在不可见的情况下工作(即,如果你想改变ORDER BY foo
的行为),我认为这意味着构建一个自定义类型,它有自己的支持函数和操作符类。Postgres中包含的citext
(case-insensitive text) extension可以作为一个有用的起点,但是这里有很多需要考虑的地方,而且很可能不是很简单。