PostgreSQL 9.1在select语句中使用collate

PostgreSQL 9.1在select语句中使用collate,postgresql,collate,Postgresql,Collate,我有一个postgresql 9.1数据库表“en_US.UTF-8”: 属性名称\u语言包含各种语言的名称。该语言由外键语言\u id指定 我创建了几个索引: /* us english */ CREATE INDEX idx_branch_language_2 ON branch_language USING btree (name_language COLLATE pg_catalog."en_US" ); /* catalan */ CREATE INDEX i

我有一个postgresql 9.1数据库表“en_US.UTF-8”:

属性名称\u语言包含各种语言的名称。该语言由外键语言\u id指定

我创建了几个索引:

/* us english */
CREATE INDEX idx_branch_language_2
    ON branch_language
    USING btree
    (name_language COLLATE pg_catalog."en_US" );

/* catalan */
CREATE INDEX idx_branch_language_5
    ON branch_language
    USING btree
    (name_language COLLATE pg_catalog."ca_ES" );

/* portuguese */
CREATE INDEX idx_branch_language_6
    ON branch_language
    USING btree
    (name_language COLLATE pg_catalog."pt_PT" );
现在,当我进行选择时,我没有得到我期望的结果

select name_language from branch_language
where language_id=42 -- id of catalan language
order by name_language collate "ca_ES" -- use ca_ES collation
这将生成一个名称列表,但不是按照我预期的顺序:

Aficions i Joguines
Agència de viatges
Aliments i Subministraments
Aparells elèctrics i il luminació
Art i Antiguitats
Articles de la llar
Bars i Restaurants
...
Tabac
Àudio, Vídeo, CD i DVD
Òptica
正如我所料,最后两个条目将出现在列表中的不同位置

创建索引是可行的。我不认为它们真的是必要的,除非你想优化性能

然而,select语句似乎忽略了以下部分:collate“ca_ES”


选择其他排序规则时也存在此问题。我试过“es_es”和“pt_pt”,但结果相似。

我在你的设计中找不到任何缺陷。我试过了

区域设置和排序 我重新考虑了这个问题。考虑一下这个。它似乎工作得很好。我甚至在本地测试服务器(Debian Squeeze上的PostgreSQL 9.1.6)中创建了locale
ca_ES.utf8
,并将locale添加到我的DB集群中:

CREATE COLLATION "ca_ES" (LOCALE = 'ca_ES.utf8');
我得到了与上面SQLFIDLE中相同的结果

请注意,排序规则名称是标识符,需要双引号以保留CamelCase拼写,如
“ca_ES”
。可能您的系统中存在与其他地区的混淆?检查您的:

通常,排序规则是从系统区域设置派生的。阅读关于这个问题的文章。如果您仍然得到不正确的结果,我将尝试更新您的系统并重新生成
“ca_ES”
的区域设置。在Debian(以及相关的Linux发行版)中,这可以通过以下方式完成:

dpkg-reconfigure locales

NFC 我还有一个想法:非标准化的UNICODE字符串

是否您的
“udio”
实际上是
“Audio”
?这就是这个角色:

SELECT U&'\0300A';
SELECT ascii(U&'\0300A');
SELECT chr(768);
了解更多有关的信息。
您必须
设置standard\u compliance\u strings=TRUE
才能像第一行一样使用Unicode字符串

请注意,某些浏览器无法正确显示非规范化的Unicode字符,并且许多字体没有适合特殊字符的字形,因此您可能在这里看不到任何内容或胡言乱语。但UNICODE允许这种胡说八道。测试以查看您得到了什么:

SELECT octet_length('̀A')  -- returns 3 (!)
SELECT octet_length('À')  -- returns 2
如果你的数据库就是这样收缩的,你需要把它处理掉,否则后果自负。解决方法是将字符串规范化为。Perl具有卓越的UNICODE foo技能,您可以在一个plperlu函数中利用它们的库在PostgreSQL中实现。我这样做是为了把我从疯狂中解救出来

请阅读这篇优秀文章中的安装说明。

阅读所有血腥的细节。

问题在于重读。您必须使用AI(重音不敏感)排序规则。查看如何在Postgre中执行此操作。在某些dbms中,它类似于ca_ES_AI。

+1它具备了一个好问题所需的一切。不幸的是,它不足以调用一个好的答案…@Henri也许可以尝试pgsql通用邮件列表()?在您的帖子中重现您的问题,但如果您在邮件列表中发帖,也可以链接回此处。我检查了“udio,Vídeo,CD I DVD”中的第一个字符,结果是:选择八位字节长度(‘À’)返回2。与“optica”相同,选择octet_length('Ò'),结果是2。在VERSION/PLATFORM COMPATIBILITY(版本/平台兼容性)下的postgresql.conf文件中——以前的postgresql版本——它的内容是#standard_compliance_strings=onithink,并希望它类似于@Henri:对不起,我的想法有点冒险。不走运。我没有主意了。据我所知,你的设置应该可以工作。你的评论给了我一些想法。然而,我的问题没有解决办法,但我的应用程序却有了些许改进。该数据库用于Django应用程序。我没有在postgresql中安装plperl,所以我不能使用David Wheelers设置,但我已经更改了模型(ORM)中的代码,所以所有unicode字符串都存储在NFC规范化的文件中。至少有一些改进…:-)
SELECT U&'\0300A';
SELECT ascii(U&'\0300A');
SELECT chr(768);
SELECT octet_length('̀A')  -- returns 3 (!)
SELECT octet_length('À')  -- returns 2