PostgreSQL:「大文字と小文字を区別しない」クエリの作成方法


338

PostgreSQLで大文字と小文字を区別しないクエリを作成する方法はありますか。たとえば、次の3つのクエリが同じ結果を返すようにしたいと思います。

SELECT id FROM groups where name='administrator'

SELECT id FROM groups where name='ADMINISTRATOR'

SELECT id FROM groups where name='Administrator'

Postgresのインストールにcitextが付属している場合は、citextタイプを試してください。大文字と小文字を区別しないテキストです
Michael Buen

2
この質問の初心者のために、公式のpostgresドキュメントへのこのリンクには、ここで与えられたすべての回答といくつかの他のオプションが含まれています。
パルティアンショット

@Arunが作成した回答に、承認された回答を再割り当てしてください。それははるかに複雑ではなく、適用後にトラブルの束を引っ張ることはありません。
zeliboba

回答:


451

使用LOWERの比較の前に小文字に文字列を変換する機能。

これを試して:

SELECT id 
  FROM groups
 WHERE LOWER(name)=LOWER('Administrator')

92
述語列(この場合は「名前」)でLOWER(または任意の関数)を使用すると、インデックスが検索できなくなることに注意することが重要です。これが大きいテーブルまたは頻繁に照会されるテーブルである場合、問題が発生する可能性があります。大文字と小文字を区別しない照合、citext、または関数ベースのインデックスを使用すると、パフォーマンスが向上します。
ジョーダン、

108
または、次のようなインデックスを作成します。CREATE INDEX idx_groups_name ON groups lower(name);
ダニエル

19
varchar_pattern_opsインデックスをLIKE 'xxx%'クエリで使用するかどうかも指定しますCREATE INDEX ix_groups_name ON groups (lower(name) varchar_pattern_ops)
sayap

10
ILIKE演算子を使用すると(以下の他の回答に示すように)、最も投票数の多い回答ですが、より簡単な方法です。
ライアン

5
ここにコメントを通って行く、提案の多くは、ここで提案しILIKE、それは、動作しますbut with slow response。計算の結果に基づいてテーブルへの高速アクセスを取得するには、これを確認するだけの人は、受け入れられた答えを使用することをお勧めします。詳細はこちらこちら
アフォラビオラルワアキンウミ2016

230

ILIKE代わりに使用LIKE

SELECT id FROM groups WHERE name ILIKE 'Administrator'

1
ILIKESpring Bootで使用した場合、Hibernateではサポートされないことに注意してください。
AnT

@AnTはorg.hibernate.dialect.PostgreSQL94Dialect、Spring Boot 2.0.6.RELEASEで動作します。しかしIntelliJはそれについて不満を言う。
Samintha Kaveesh

134

最も一般的なアプローチは、検索文字列とデータを小文字または大文字にすることです。しかし、それには2つの問題があります。

  1. 英語で動作しますが、すべての言語で動作するわけではありません。(たぶんほとんどの言語でさえそうではありません。)すべての小文字に対応する大文字があるわけではありません。すべての大文字に対応する小文字があるわけではありません。
  2. lower()やupper()などの関数を使用すると、順次スキャンが行われます。インデックスは使用できません。テストシステムでは、lower()を使用すると、インデックスを使用できるクエリよりも約2000倍時間がかかります。(テストデータには10万行強があります。)

より効果的かもしれない、使用頻度の低いソリューションが少なくとも3つあります。

  1. 主に大文字と小文字を区別しないデータ型の動作を模倣するcitextモジュールを使用します。そのモジュールを読み込んだら、で大文字と小文字を区別しないインデックスを作成できますCREATE INDEX ON groups (name::citext);。(ただし、以下を参照してください。)
  2. 大文字と小文字を区別しない照合を使用します。これは、データベースを初期化するときに設定されます。大文字と小文字を区別しない照合を使用すると、クライアントコードからほぼすべての形式を受け入れることができ、引き続き有用な結果が返されます。(また、大文字と小文字を区別するクエリを実行できないことも意味します。まあ。)
  3. 関数インデックスを作成します。を使用して小文字のインデックスを作成しますCREATE INDEX ON groups (LOWER(name));。ことをやった、あなたのようなクエリでインデックスを利用することができSELECT id FROM groups WHERE LOWER(name) = LOWER('ADMINISTRATOR');、またはSELECT id FROM groups WHERE LOWER(name) = 'administrator';あなたはする必要が覚えているものの、LOWER()を使用します。

citextモジュールは、大文字と小文字を区別しない真のデータ型を提供しません。代わりに、各文字列が小文字であるかのように動作します。つまり、lower()上記の3のように、各文字列を呼び出したかのように動作します。利点は、プログラマが小文字の文字列を覚えておく必要がないことです。ただし、citextを使用する前に、ドキュメントの「文字列比較動作」と「制限」のセクションを読む必要があります。


1
#1について:2つの異なる文字列になるので、問題にはならないはずです(col = 'a'やのように考えてくださいcol = 'b')。#2について:あなたが言ったように、式にインデックスを作成することができるので、それは実際には問題ではありません。しかし、照合順序を変更することが最も可能性の高い解決策であることに同意します。
Vincent Savard、2011

5
大文字小文字を区別しない照合がPostgreSQLの組み込み照合であると教えてもらえますか?私はこれをオプションと見なしていますが、ネット上のPostgresの大文字と小文字を区別しない照合について何も見つかりませんか?
khorvat 2013

1
@AnupShah:いいえ、それは言っていません。WindowsでPostgreSQLを実行していません。9.4のドキュメントには次のように書かれています。PostgreSQLがどの照合順序を使用できると見なすかを確認できますselect * from pg_collation;
マイクシェリル「キャットリコール」、

1
@Matthieu:これは、私が知っている主題への最良の導入(および注意)です。パート1 –テキスト
マイクシェリル「キャットリコール」


95

使用できますILIKE。すなわち

SELECT id FROM groups where name ILIKE 'administrator'

それは正しく、私には問題なく機能しています。私はMAC OS X(Mountain Lion)を使用しています。
ADJ 2013

5
これは機能しますが、応答が遅くなります。計算結果に基づいてテーブルに高速にアクセスするには、lower関数を使用することをお勧めします。よりご覧ください詳細
アフォラビOlaoluwa Akinwumi

1
@AfolabiOlaoluwaAkinwumiは、基本的に、既知の値をフィルタリングするのではなく、結果を検索するかどうかに関係します。後者の場合、単一の均一なケースをデータレベルで永続化して、等価演算子が機能できるようにする必要があります。[個人的な推奨事項は、型コード値の大文字の場合]
Chris Marisic

53

また、ILIKEキーワードを読むこともできます。SQL標準に準拠していなくても、非常に役立つ場合があります。詳細については、こちらを参照してください:http : //www.postgresql.org/docs/9.2/static/functions-matching.html


9
ここで注意すべきことは、悪意のあるユーザー入力です。のようなクエリを実行する場合はemail ILIKE 'user-input-email-here'、必ずユーザー入力をエスケープしてください。それ以外の場合、人々は何にでもマッチする%のような文字を入力できます。
Matt De Leon

2
@MattDeLeonこんにちは。よく言った。しかし、私はあなたに尋ねたいのですが、私が使用していてILIKEprepared statementsこれが私を守るのですsql injectionか?
slevin 2013年

わかりません。準備したステートメントにエスケープ文字列を送信する必要があると思います。
Matt De Leon

1
「LIKEの代わりにキーワードILIKEを使用して、アクティブなロケールに応じて大文字と小文字を区別せずに一致させることができます。これはSQL標準にはありませんが、PostgreSQLの拡張機能です。」9.3の魅力のように機能します
Aleksey Deryagin 2014

1
ILIKEはlower(column_name) like %expression%。より遅いです。
Patryk Imosa 2017年

28

次のようなPOSIX正規表現を使用することもできます。

SELECT id FROM groups where name ~* 'administrator'

SELECT 'asd' ~* 'AsD' 戻り値 t


1
同じ問題がありました。PostgreSQLデータベースで大文字と小文字を区別しない検索が必要でした。ユーザー入力文字列を正規表現に変換することを考えました。=またはLIKEの代わりに〜*を使用しても問題なく動作しました。新しいインデックスや列などを作成する必要はありませんでした。確かに、正規表現検索は単純なバイト比較よりも低速ですが、パフォーマンスへの影響は、2つのデータセット(1つは検索のためだけに小文字または大文字)を処理し、対応する元のデータを取得する必要があるほど大きくはないと思います他のセットからのデータ)。しかもこれはすっきり!
Cyber​​knight、2015年

1
結構ですが、たとえばregexp_matches()をどのように使うのですか?
WKT

postgres docsによると:演算子~~はLIKEと同等であり、~~ *はILIKEに対応します。NOT LIKEおよびNOT ILIKEをそれぞれ表す!~~および!~~ *演算子もあります。これらの演算子はすべてPostgreSQL固有です。
sh4

括弧がテキストに含まれていると問題が発生しましたが、機能しません。例:「コード(LC)」
Oshan Wisumperuma

8

使用~*INSTRの機能で、パフォーマンスが大幅に向上させることができます。

SELECT id FROM groups WHERE name ~* 'adm'

ORが「adm」と等しい名前を含む行を返します。


1
やあ、ロビン、SOへようこそ。James Brownの回答はすでにこの解決策を提案しています。さらに、提案された回答は正規表現を利用しません。
ラファエル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.