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

时间:2011-10-17 14:25:15

标签: 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,
    ....
)

属性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" );

现在当我选择时,我没有得到我期待的结果。

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语句似乎忽略了部分:collat​​e“ca_ES”。

当我选择其他排序规则时,也存在此问题。我尝试了“es_ES”和“pt_PT”,但结果相似。

2 个答案:

答案 0 :(得分:3)

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

区域设置和整理

我重新回答了这个问题。考虑一下test case on sqlfiddle。它似乎工作得很好。我甚至在我的本地测试服务器(Debian Squeeze上的PostgreSQL 9.1.6)中创建了语言环境ca_ES.utf8,并将语言环境添加到我的数据库集群中:

CREATE COLLATION "ca_ES" (LOCALE = 'ca_ES.utf8');

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

请注意,归类名称是标识符,需要加双引号以保留CamelCase拼写,如"ca_ES"。也许你的系统中的其他语言环境有些混乱?检查您的available collations

SELECT * FROM pg_collation;

通常,归类规则源自系统区域设置。阅读details in the manual here。如果仍然得到不正确的结果,我会尝试更新您的系统并重新生成"ca_ES"的区域设置。在Debian(和相关的Linux发行版)中,这可以通过以下方式完成:

dpkg-reconfigure locales

NFC

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

您的'Àudio'实际上是'̀ ' || 'Audio'吗?那将是这个角色:

SELECT U&'\0300A';
SELECT ascii(U&'\0300A');
SELECT chr(768);

详细了解acute accent in wikipedia 您必须SET standard_conforming_strings = TRUE使用第一行中的Unicode字符串。

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

SELECT octet_length('̀A')  -- returns 3 (!)
SELECT octet_length('À')  -- returns 2

如果这是您的数据库签约的,那么您需要摆脱它或承担后果。解决方法是将字符串规范化为NFC。 Perl具有出色的UNICODE-foo技能,你可以在plperlu函数中使用它们的库来在PostgreSQL中完成它。我这样做是为了让我免于疯狂。

阅读这篇关于UNICODE normalization in PostgreSQL by David Wheeler的优秀文章中的安装说明 阅读有关Unicode Normalization Forms at unicode.org的所有详细信息。

答案 1 :(得分:1)

问题在于重点。您必须使用AI(不区分重音)排序规则。检查以了解如何在Postgre中进行操作。在某些dbms中,它类似于ca_ES_AI。