Microsoft SQL Serverでは、(データベース、テーブル、または列に対して)「アクセントを区別しない」照合を指定できます。つまり、次のようなクエリが可能です。
SELECT * FROM users WHERE name LIKE 'João'
名前がJoao
の行を見つけます。
naccent_string contrib関数を使用してPostgreSQLの文字列からアクセントを取り除くことができることは知っていますが、PostgreSQLはこれらの「アクセントに依存しない」照合をサポートしているので上記のSELECT
が機能するのでしょうか。
そのために unaccent module を使用します。これはリンク先とはまったく異なります。
unaccentは、語彙素からアクセント(発音区別符号)を削除するテキスト検索辞書です。
以下を使用して、データベースごとに1回インストールします。
_CREATE EXTENSION unaccent;
_
次のようなエラーが表示された場合:
エラー:拡張制御ファイル "/usr/share/postgresql/9.x/extension/unaccent.control"を開けませんでした:そのようなファイルまたはディレクトリはありません
この関連する回答の指示に従って、データベースサーバーにcontribパッケージをインストールします。
とりわけ、サンプルで使用できるunaccent()
関数を提供します(LIKE
は必要ないようです)。
_SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
_
その種類のクエリにインデックスを使用するには、 式のインデックス を作成します。 ただし、、Postgresはインデックスに対してIMMUTABLE
関数のみを受け入れます。関数が同じ入力に対して異なる結果を返すことができる場合、インデックスはサイレントにブレークする可能性があります。
unaccent()
only STABLE
not IMMUTABLE
残念ながら、unaccent()
はSTABLE
ではなくIMMUTABLE
のみです。 pgsql-bugsのこのスレッド によると、これはthreeの理由によるものです:
search_path
_にも依存しますが、これは簡単に変更できます。一部のチュートリアル Webで、関数のボラティリティをIMMUTABLE
に変更するように指示します。このブルートフォース方式は、特定の条件下で機能しなくなる可能性があります。
simple IMMUTABLE
wrapper関数 (過去に自分でやったように)を提案する人もいます。
2つのパラメーターを持つバリアントIMMUTABLE
を使用する辞書を明示的に宣言するかどうかについては、継続的な議論があります。 here または here を読んでください。
別の代替手段は、Githubで提供される MusicbrainzによるIMMUTABLE unaccent()
関数 を持つこのモジュールです。自分でテストしていない。私はより良いアイデアを思いついたと思う:
私は、少なくとも他のソリューションと同じくらい効率的ですが、より安全なアプローチを提案します:2パラメータ形式と「ハード関数と辞書のスキーマ:
_CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1) -- schema-qualify function and dictionary
$func$ LANGUAGE sql IMMUTABLE;
_
public
は、拡張機能をインストールしたスキーマです(public
がデフォルトです)。
以前は、関数に_SET search_path = public, pg_temp
_を追加していました-辞書もスキーマで修飾できることを発見するまで、 これは現在(10ページ)文書化されていません です。このバージョンは、pg 9.5およびpg 10でのテストでは少し短く、約2倍高速です。
IMMUTABLE
で宣言された関数は、それを許可するために本体で不変ではない関数を呼び出さない可能性があるため、更新バージョンでは function inlining が許可されていません。このIMMUTABLE
関数でexpression indexを使用している間は、パフォーマンスにはほとんど問題ありません。
_CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
_
クライアントプログラムのセキュリティは、Postgres 10.3/9.6.8などで強化されています。インデックスで使用するときに示されるように、関数と辞書をスキーマ修飾するためにneedを使用します。見る:
インデックスに一致するようにクエリを調整します(クエリプランナーが使用できるように)。
_SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
_
適切な式に関数は必要ありません。 _'Joao'
_のようなアクセントのない文字列を直接指定できます。
Postgres9.5またはそれ以前では、「Œ」や「ß」などの合字を手動で展開する必要があります(必要な場合)unaccent()
は常にsingle文字を置換します。
_SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
_
このアップデートはunaccentに更新されます Postgresで9.6:
_
contrib/unaccent
_の標準_unaccent.rules
_ファイルを拡張して、Unicodeで認識されているすべての発音区別符号を処理し、合字を正しく展開します(Thomas Munro、LéonardBenedetti)
大胆な強調鉱山。今、私たちは得る:
_SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
_
LIKE
またはILIKE
任意のパターンで、これをモジュールと組み合わせます _pg_trgm
_ PostgreSQL 9.1以降。トライグラムGIN(通常は望ましい)またはGist式インデックスを作成します。 GINの例:
_CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
_
次のようなクエリに使用できます。
_SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
_
GINインデックスとGistインデックスは、プレーンなbtreeよりも保守が高価です。
左に固定されたパターンには、より簡単なソリューションがあります。パターンマッチングとパフォーマンスの詳細:
_pg_trgm
_は、有用な 「類似性」(_%
_)および「距離」(_<->
_) の演算子も提供します。
Trigramインデックスは、_~
_などの単純な正規表現もサポートしています。および大文字と小文字を区別しないILIKE
とのパターンマッチング:
PostgreSQLは、そのような照合(アクセントを区別するかどうかに関係なく)をサポートしません。これは、物がバイナリに等しい場合を除き、比較が同等を返すことができないためです。これは、内部的にハッシュインデックスのようなものに多くの複雑さを導入するためです。このため、厳密な意味での照合は順序付けにのみ影響し、平等には影響しません。
FTSの場合、unaccent
を使用して独自の辞書を定義できます。
CREATE EXTENSION unaccent;
CREATE TEXT SEARCH CONFIGURATION mydict ( COPY = simple );
ALTER TEXT SEARCH CONFIGURATION mydict
ALTER MAPPING FOR hword, hword_part, Word
WITH unaccent, simple;
その後、機能インデックスを使用してインデックスを作成できます。
-- Just some sample data...
CREATE TABLE myTable ( myCol )
AS VALUES ('fóó bar baz'),('qux quz');
-- No index required, but feel free to create one
CREATE INDEX ON myTable
USING Gist (to_tsvector('mydict', myCol));
非常に簡単にクエリできるようになりました
SELECT *
FROM myTable
WHERE to_tsvector('mydict', myCol) @@ 'foo & bar'
mycol
-------------
fóó bar baz
(1 row)
こちらもご覧ください
unaccent
module は、FTS統合なしで単独で使用することもできます。そのためには、 Erwin's answer