私の質問のきっかけは、一致する文字列がlower()
の1つ以上のインスタンスにラップされているかどうかに関係なく、citext
列から選択するときにPostgreSQLが一貫して動作することを望んでいたことです。 (そのようなラッピングは私のコントロールを超えています)。そうではないようです。 (もちろん、私のテストが無効であるか、基本的な概念を誤解している可能性は十分にあります。)
CREATE EXTENSION IF NOT EXISTS citext;
CREATE TABLE users (id int, email citext);
INSERT INTO users(id, email) VALUES
(1, '[email protected]');
citext
タイプを使用すると予想されるように、小文字のバリアントは次の結果をもたらします。
# select * from users where email = '[email protected]';
id | email
----+------------------
1 | [email protected]
(1 row)
=
演算子をlike
に変更すると、次の結果が得られます。
select * from users where email like lower('[email protected]');
id | email
----+------------------
1 | [email protected]
(1 row)
「逆」と同じように:
# select * from users where lower(email) = '[email protected]';
id | email
----+------------------
1 | [email protected]
(1 row)
lower()
で両方の値をラップするのと同じように:
# select * from users where lower(email) = lower('[email protected]');
id | email
----+------------------
1 | [email protected]
(1 row)
では、なぜ次のクエリはこのインスタンスで結果を返さないのですか?
# select * from users where email = lower('[email protected]');
id | email
----+-------
(0 rows)
基本的に、値を比較するときに内部的にlowerを呼び出します。
有効な言葉は「本質的に」のようです。このステートメントは、次のことを意味しますが、結果は得られます。
select * from users where lower(email) = lower(lower('[email protected]'));
id | email
----+------------------
1 | [email protected]
(1 row)
これは、上記のドキュメントのLimitations
セクションにある次の警告に関連している可能性がありますか?
citextの大文字小文字の区別の動作は、データベースのLC_CTYPE設定によって異なります。
# SHOW LC_CTYPE;
lc_ctype
-------------
en_US.UTF-8
(1 row)
この点に関する説明は大歓迎です。
tldr;大文字と小文字を区別しないものと大文字と小文字を区別するものを比較する場合は、明示的にする必要があります。text
は明示的に大文字と小文字を区別し、citext
は明示的に大文字と小文字を区別しません。あなたshould両側にキャストを提供し、明示的に
lower()
に関するいくつかのこと
lower()
が入力されますtext
の場合、常にtext
を返します。他のいくつかのポイント
unknown
です)。この場合のタイプは次のとおりです。
_-- text = unknown
-- unknown promoted to text, this has nothing to do with citext
lower(email) = '[email protected]';
-- text = text
-- this has nothing to do with citext
lower(email) = lower('[email protected]');
-- text = text
-- this has nothing to do with citext
lower(email) = lower(lower('[email protected]'));
-- citext LIKE text
-- LIKE is smart `operator ~~(citext,text)` via `texticlike`
-- WORKS
email like lower('[email protected]');
-- citext = unknown
-- unknown promoted to citext, there is an `operator =(citext,citext)`
-- WORKS
email = '[email protected]';
-- citext = text
-- citext promoted to text, there is no `operator =(citext,text)`
-- FAILS
email = lower('[email protected]');
_
要約すると、operator =(citext,citext)
があります。だからあなたはできる
_email = lower('[email protected]')::citext;
_
必要に応じて、または_=
_を大文字と小文字を区別するルートではなく大文字と小文字を区別しないルートに設定する独自の演算子を定義できます。でもそれは恐ろしい練習だと思いますが、私はいつもキャストします。