7

postgresql9.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

予想通り、最後の2つのエントリはリストの異なる位置に表示されます。

インデックスの作成は機能します。パフォーマンスを最適化する必要がない限り、これらは本当に必要ではないと思います。

ただし、selectステートメントは「ca_ES」を照合する部分を無視しているようです。

この問題は、他の照合を選択した場合にも発生します。「es_ES」と「pt_PT」を試しましたが、結果は似ています。

4

2 に答える 2

3

あなたのデザインに欠陥は見つかりません。私が試してみました。

ロケールと照合

私はこの質問を再検討しました。sqlfiddleのこのテストケースを考えてみましょう。それはうまくいくようです。ca_ES.utf8ローカルテストサーバー(DebianSqueezeのPostgreSQL9.1.6)でロケールを作成し、そのロケールをDBクラスターに追加しました。

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

上記のsqlfiddleで見られるのと同じ結果が得られます。

照合名は識別子であり、キャメルケースのスペルを保持するために二重引用符で囲む必要があることに注意してください"ca_ES"。システム内の他のロケールとの混乱があったのではないでしょうか。利用可能な照合を確認してください:

SELECT * FROM pg_collation;

通常、照合ルールはシステムロケールから派生します。詳細については、こちらのマニュアルをご覧ください。それでも間違った結果が得られる場合は、システムを更新して、のロケールを再生成しようとします"ca_ES"。Debian(および関連するLinuxディストリビューション)では、これは次の方法で実行できます。

dpkg-reconfigure locales

NFC

もう1つのアイデアがあります。正規化されていないUNICODE文字列です。

それはあなた'Àudio'が実際にいるということ'̀ ' || 'Audio'でしょうか?それはこのキャラクターになります:

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

ウィキペディアでアキュートアクセントの詳細をご覧ください。最初の行のようにUnicode文字列を使用する
必要があります。SET standard_conforming_strings = TRUE

一部のブラウザは正規化されていないUnicode文字を正しく表示できず、多くのフォントには特殊文字の適切なグリフがないため、ここに何も表示されないか、ぎこちないことがあります。しかし、UNICODEはそのナンセンスを考慮に入れています。あなたが得たものを確認するためにテストしてください:

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

それがあなたのデータベースが契約しているものであるならば、あなたはそれを取り除くか、結果に苦しむ必要があります。治療法は、文字列をNFCに正規化することです。Perlには優れたUNICODE-fooスキルがあり、plperlu関数でライブラリを利用してPostgreSQLで実行できます。私は狂気から私を救うためにそれをしました。

DavidWheelerによるPostgreSQLでのUNICODE正規化に関するこの優れた記事のインストール手順をお読みください。unicode.orgでUnicode正規化フォーム
に関するすべての厄介な詳細を読んでください。

于 2011-10-20T01:24:59.167 に答える