★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

F.8. citext

citextモジュールは、大文字小文字の区別がない文字列型を提供します。 これは値の比較の際、基本的に内部でlowerを呼び出します。 この他はほぼtextと同様に動作します。

ヒント

このモジュールの代わりに非決定論的照合順序(23.2.2.4参照)を使うことを検討してください。 大文字小文字を区別しない比較、アクセントを区別しない比較、その他の組み合わせに対して使えますし、より多くのユニコードの特別な場合を正しく扱います。

F.8.1. 原理

PostgreSQLにおいて大文字小文字の区別のない比較を行う標準的な手法は、値を比べる際に以下のようにlower関数を使用することでした。例です。

SELECT * FROM tab WHERE lower(col) = LOWER(?);

これはまあまあ動作しますが、数多くの欠点があります。

  • 作成するSQL文を冗長にします。 また常に列と問い合わせの値両方にlowerを使用することを忘れないようにしなければなりません。

  • lowerを使用して関数インデックスを作成していない限り、インデックスを使用しません。

  • UNIQUEまたはPRIMARY KEYとして列を宣言するのであれば、暗黙的に生成されるインデックスは大文字小文字を区別します。 このため、大文字小文字を区別しない検索では使えず、また、大文字小文字を区別しない一意性を強制させられません。

citextデータ型によりSQL問い合わせ内のlower呼び出しを省くことができます。 さらに、大文字小文字の区別がない主キーを実現できます。 citexttextと同様にロケールも考慮します。 つまり大文字と小文字のマッチングは、LC_CTYPEデータベース設定の規則に依存します。 ここでも、この動作はlowerを使用した問い合わせと同一です。 しかしこのデータ型により、ロケールの考慮は透過的に行われますので、問い合わせで特殊なことを行うことを覚えておく必要はありません。

F.8.2. 使用方法

簡単な例を示します。

CREATE TABLE users (
    nick CITEXT PRIMARY KEY,
    pass TEXT   NOT NULL
);

INSERT INTO users VALUES ( 'larry',  sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Tom',    sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Damian', sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'NEAL',   sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Bjørn',  sha256(random()::text::bytea) );

SELECT * FROM users WHERE nick = 'Larry';

SELECT文は、nick列がlarryに設定され、問い合わせがLarryに対してであっても、1つのタプルを返します。

F.8.3. 文字列比較の動作

citextはそれぞれの文字列を(lowerが呼ばれますが)小文字に変換して結果を普通に比較します。 よって、例えばlowerで小文字にした場合に同じ結果となるような2つの文字列が等しいとみなされます。

大文字小文字の区別のない照合をできる限り正確にエミュレートするために、数多くのcitext独自版の各種文字列処理演算子と関数があります。 したがって、例えば正規表現演算子~および~*は、citextに適用する時に同じ動作を提供します。 これら両方は大文字小文字を区別することなくマッチします。 !~!~*だけではなくLIKE演算子、~~~~*!~~!~~*でも同じことが言えます。 もし大文字小文字を区別して比較したい場合は、演算子の引数をtextにキャストすることができます。

引数がcitextであれば、同様にして以下の関数は大文字小文字を区別しない一致を実行します。

  • regexp_match()

  • regexp_matches()

  • regexp_replace()

  • regexp_split_to_array()

  • regexp_split_to_table()

  • replace()

  • split_part()

  • strpos()

  • translate()

正規表現関数(RegExp関数)では、大文字小文字を区別して一致させたい場合cフラグを付けて、強制的に大文字小文字を区別して一致させることができます。 そうしないと、大文字小文字を区別させたい場合にはこれらの関数のいずれかを使用する前段階でtextにキャストしなければなりません。

F.8.4. 制限

  • citextの大文字小文字を区別しない動作は使用するデータベースのLC_CTYPEに依存します。 どのように値を比較するかは、データベースが作成されたときに決定されます。 Unicode標準の定義という観点では、真に大文字小文字の区別がないわけではありません。 実質的に何を意味しているかというと、使用している照合が十分なものであれば、citextによる比較も十分なものになるはずです。 しかしデータベースに様々な言語でデータを格納している場合は、ある言語のユーザは照合が他の言語用のものであった場合想定外の問い合わせ結果を得るかもしれません。

  • PostgreSQL 9.1では、COLLATE指定をcitext列もしくはデータ値に付け加えることができます。 現状では、citext演算子は大文字小文字を含んだ文字列を比較する際に、デフォルトではないCOLLATE指定を重んじます。 しかし、最初の小文字変換はデータベースのLC_CTYPE設定にしたがって、常に実行されます(つまり、COLLATE "default"が指定されたようになります) これは、両方のステップが入力されたCOLLATE指定に従うように、将来のリリースにおいて変更されるでしょう。

  • 演算子関数およびB-tree比較関数でデータの複製を作成しそれを比較のために小文字に変換しなければなりませんので、citexttextほど効率的ではありません。 しかし大文字小文字の区別をしない一致をさせるためにlowerを使用する場合よりかなり効率的です。

  • citextは、ある文脈では大文字小文字の区別を行い、またある文脈では大文字小文字の区別を行わない比較をする必要がある場合、あまり役に立ちません。 標準的な解法はtext型を使用し、大文字小文字を区別する比較が必要であれば手作業でlower関数を使用することです。 これは大文字小文字を区別しない比較の必要性がまれであれば、問題なく動作します。 大文字小文字を区別しない比較がほとんどで、大文字小文字を区別する比較の必要性がまれである場合は、データをcitextとして格納し、大文字小文字を区別する比較の際にその列を明示的にtextにキャストすることを検討してください。 どちらの場合でも、2種類の検索の両方を高速にするために2つのインデックスを作成しなければならないでしょう。

  • citext演算子を含んだスキーマは、現在のsearch_path(典型的にはpublic)に 存在しなければいけません。もし無い場合は通常の大文字小文字が区別されるtext比較が代わりに呼び出されます。

  • 比較のために文字列を小文字にする方法は、例えば、大文字1つに対応する小文字が2つある場合等、ユニコードの特別な場合を正しく扱えないことがあります。 ユニコードはこの理由で大文字小文字の対応関係大文字小文字の畳み込みを区別します。 正しくその場合を扱うには、citextの代わりに非決定論的照合順序を使ってください。

F.8.5. 作者

David E. Wheeler

Donald Fraserによるcitextモジュール原本からのヒント