PostgreSQL 9.1在select语句中使用collat​​e

Hen*_*nri 7 postgresql collate

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

CREATE TABLE branch_language
(
    id serial NOT NULL,
    name_language character varying(128) NOT NULL,
    branch_id integer NOT NULL,
    language_id integer NOT NULL,
    ....
)
Run Code Online (Sandbox Code Playgroud)

name_language属性包含各种语言的名称.该语言由外键language_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" );
Run Code Online (Sandbox Code Playgroud)

现在,当我做一个选择时,我没有得到我期待的结果.

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
Run Code Online (Sandbox Code Playgroud)

这会生成一个名称列表,但不会按照我预期的顺序生成:

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
Run Code Online (Sandbox Code Playgroud)

正如我所料,最后两个条目出现在列表中的不同位置.

创建索引有效.除非您想要优化性能,否则我认为它们不是必需的.

然而,select语句似乎忽略了部分:collat​​e"ca_ES".

当我选择其他排序规则时,也存在此问题.我试过"es_ES"和"pt_PT",但结果相似.

Erw*_*ter 3

我在你的设计中找不到缺陷。我努力了。

\n

区域设置和排序规则

\n

我重新审视了这个问题。考虑sqlfiddle 上的这个测试用例。看起来效果很好。我什至在本地测试服务器(Debian Squeeze 上的 PostgreSQL 9.1.6)中创建了区域设置ca_ES.utf8,并将区域设置添加到了我的数据库集群中:

\n
CREATE COLLATION "ca_ES" (LOCALE = \'ca_ES.utf8\');\n
Run Code Online (Sandbox Code Playgroud)\n

我得到的结果与上面的 sqlfiddle 中看到的结果相同。

\n

请注意,排序规则名称是标识符,需要用双引号括起来以保留 CamelCase 拼写,例如"ca_ES". 也许与您系统中的其他区域设置存在一些混淆?检查您可用的排序规则

\n
SELECT * FROM pg_collation;\n
Run Code Online (Sandbox Code Playgroud)\n

通常,排序规则源自系统区域设置。请阅读此处手册中的详细信息。如果您仍然得到不正确的结果,我会尝试更新您的系统并重新生成"ca_ES". 在 Debian(以及相关的 Linux 发行版)中,可以通过以下方式完成:

\n
dpkg-reconfigure locales\n
Run Code Online (Sandbox Code Playgroud)\n
\n

近场通信

\n

我还有另一个想法:非标准化 UNICODE strings

\n

难道你的\'\xc3\x80udio\'就是事实\'\xcc\x80 \' || \'Audio\'吗?那就是这个角色:

\n
SELECT U&\'\\0300A\';\nSELECT ascii(U&\'\\0300A\');\nSELECT chr(768);\n
Run Code Online (Sandbox Code Playgroud)\n

在维基百科中了解更多有关尖锐口音的信息。
\n您必须SET standard_conforming_strings = TRUE像第一行一样使用 Unicode 字符串。

\n

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

\n
SELECT octet_length(\'\xcc\x80A\')  -- returns 3 (!)\nSELECT octet_length(\'\xc3\x80\')  -- returns 2\n
Run Code Online (Sandbox Code Playgroud)\n

如果你的数据库已经收缩了,你需要摆脱它,否则后果自负。解决方法是将您的字符串标准化为NFC。Perl 具有出色的 UNICODE-foo 技能,您可以在 plperlu 函数中利用它们的库在 PostgreSQL 中执行此操作。我这样做是为了让我免于疯狂。

\n

阅读David Wheeler 撰写的这篇有关 PostgreSQL 中 UNICODE 规范化的优秀文章中的安装说明。\n请访问 unicode.org 阅读有关 Unicode 规范化形式
的所有详细信息。

\n