MySQLでSQLの大文字と小文字を区別する文字列比較を行うにはどうすればよいですか?


285

大文字と小文字が混在する5文字を返す関数があります。この文字列に対してクエリを実行すると、大文字小文字に関係なく値が返されます。

MySQL文字列クエリで大文字と小文字を区別するにはどうすればよいですか?



8
BINARYは大文字と小文字を区別する比較とは異なることに注意してください。select 'à' like 'a' //はtrueを返しますselect 'à' like BINARY 'a' //はfalseを返します!!! select 'à' like 'a' COLLATE latin1_general_cs // trueを返すため、大文字と小文字を区別する比較にBINARYを使用するという提案は正しくありません。
cquezel 2011

3
@cquezel:つまり、[BINARY 'a'のようなselect 'à']はtrueを返す必要があると言っているのですか?いずれにせよ、これは大文字と小文字を区別する比較と何の関係がありますか?
Francisco Zarabozo 2013年

3
@FranciscoZarabozo以下の一部の人々は、BINARY比較を使用して大文字と小文字を区別する比較を行うことを提案しました。他の言語では、BINARYは大文字と小文字を区別するものと同じではないため、これはおそらく期待どおりに機能しないことを指摘しました。
cquezel 2014年

3
@cquezel「à」は「a」とは別の文字だと思います。したがって、2つの間の比較は、実際にはどのような場合でも偽になるはずです。
ステファン

回答:


159

http://dev.mysql.com/doc/refman/5.0/en/case-sensitiveivity.html

デフォルトの文字セットと照合はlatin1とlatin1_swedish_ciであるため、非バイナリ文字列の比較では、デフォルトで大文字と小文字が区別されません。つまり、col_name LIKE 'a%'で検索すると、Aまたはaで始まるすべての列の値が取得されます。この検索で​​大文字と小文字を区別するには、オペランドの1つに大文字と小文字の区別またはバイナリ照合があることを確認してください。たとえば、どちらもlatin1文字セットを持つ列と文字列を比較する場合は、COLLATE演算子を使用して、いずれかのオペランドにlatin1_general_csまたはlatin1_bin照合順序を設定できます。

col_name COLLATE latin1_general_cs LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_general_cs
col_name COLLATE latin1_bin LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_bin

常に大文字と小文字を区別する方法で列を処理する場合は、大文字と小文字を区別する照合またはバイナリ照合で列を宣言します。


4
phpmyadminでこれを行う方法に関するヒントはありますか?
StevenB

4
@StevenB:列の[編集]ボタンをクリックし、[照合順序]を設定します-> i.imgur.com/7SoEw.png
11

32
:あなたのようなビンcolationを使用することができ@BTにメイクのutf8列の大文字と小文字を区別SELECT 'email' COLLATE utf8_bin = 'Email'
piotrekkr

@drudge大文字と小文字を区別する照合で列をどのように宣言しますか?
ステファン

1
@StephaneEybert大文字と小文字を区別する必要がある場合は、ut8テーブルのフィールドにvarcharではなくvarbinaryを使用して運が良かったです。HTH
アンドリューT

724

良い知らせは、大文字と小文字を区別するクエリを作成する必要がある場合、非常に簡単に実行できることです。

SELECT *  FROM `table` WHERE BINARY `column` = 'value'

34
これはまさに私が探していたものです。できればもっと高くしたい。質問ですが、これはパフォーマンスにどのような影響を与えますか?私はそれを限られたレポートのものに使用しているので、私の場合は重要ではありませんが、私は興味があります。
adjwilli 2012

23
なぜこれが答えではないのですか?これもまさに私が必要としていたことです。
Art Geigel 2013

7
@adjwilli列がインデックスの一部であった場合、そのインデックスに依存するクエリのパフォーマンスが低下します。パフォーマンスを維持するには、実際にテーブルを変更する必要があります。
dshin

6
ウムラウトを追加するために結合文字を使用するなど、異なる表現の同じ文字を含むUTF-8文字列に対してこれは何をしますか?これらのUTF-8文字列は、convert(char(0x65,0xcc,0x88) using utf8)(つまりe¨追加あり)とconvert(char(0xc3,0xab) using utf8)(つまり、ë)として同等に扱うことができますが、追加BINARYすると、等しくなくなります。
mvds 2015年

3
パフォーマンスの例として、私のクエリは3,5ms(無視できる)から1.570ms(これは約1秒半です)に渡り、約180万行のテーブルをクエリします。
リュイスSuñol

64

クレイグホワイトが投稿した回答には、大きなパフォーマンスペナルティがあります。

SELECT *  FROM `table` WHERE BINARY `column` = 'value'

インデックスを使用しないためです。したがって、https: //dev.mysql.com/doc/refman/5.7/en/case-sensitiveivity.htmlのように、テーブルの照合順序を変更する必要があります

または

最も簡単な修正は、BINARY値を使用することです。

SELECT *  FROM `table` WHERE `column` = BINARY 'value'

例えば。

mysql> EXPLAIN SELECT * FROM temp1 WHERE BINARY col1 = "ABC" AND col2 = "DEF" ;
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | temp1  | ALL  | NULL          | NULL | NULL    | NULL | 190543 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+

VS

mysql> EXPLAIN SELECT * FROM temp1 WHERE col1 = BINARY "ABC" AND col2 = "DEF" ;
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
| id | select_type | table | type  | possible_keys | key           | key_len | ref  | rows | Extra                              |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
|  1 | SIMPLE      | temp1 | range | col1_2e9e898e | col1_2e9e898e | 93      | NULL |    2 | Using index condition; Using where |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
enter code here

セット内の1行(0.00秒)


これは、10.3.22 -MariaDB(libmysql-5.6.43を使用)では大文字と小文字が区別されないようです
user10398534

40

=演算子を使用する代わりに、LIKEまたはLIKE BINARYを使用することができます

// this returns 1 (true)
select 'A' like 'a'

// this returns 0 (false)
select 'A' like binary 'a'


select * from user where username like binary 'a'

状態は「A」ではなく「A」になります


これは、10.3.22 -MariaDB(libmysql-5.6.43を使用)では大文字と小文字が区別されないようです
user10398534

17

BINARYを使用する前にインデックスを使用するには、大きなテーブルがある場合に、次のようにします。

SELECT
   *
FROM
   (SELECT * FROM `table` WHERE `column` = 'value') as firstresult
WHERE
   BINARY `column` = 'value'

サブクエリを実行すると、大文字と小文字が区別されない非常に小さなサブセットが生成され、そのサブセットで大文字と小文字を区別する一致のみを選択します。


上記はあなたのデータに依存してのみ役立つと言うことはコメントする価値があります-あなたの大文字と小文字を区別しない検索は潜在的にかなり大きなデータのサブセットを返すかもしれません。
BrynJ 2017

15

クエリ対象の列の照合順序を変更せずに大文字と小文字を区別する文字列比較を実行する最も正しい方法は、列が比較される値の文字セットと照合順序を明示的に指定することです。

select * from `table` where `column` = convert('value' using utf8mb4) collate utf8mb4_bin;

なぜ使用しないのbinaryですか?

binary演算子はエンコードされた文字列の実際のバイトを比較するため、演算子の使用はお勧めできません。異なる文字セットを使用してエンコードされた2つの文字列の実際のバイトを比較すると、同じと見なされるべき2つの文字列は等しくない場合があります。たとえば、latin1文字セットを使用する列があり、サーバー/セッションの文字セットがutf8mb4である場合、その列を 'café'などのアクセントを含む文字列と比較すると、同じ文字列を含む行とは一致しません。これは、latin1éはバイトとしてエンコードされます0xE9が、utf82バイトであるためです0xC3A9

なぜconvert同様に使用するのcollateですか?

照合順序は文字セットと一致する必要があります。したがって、サーバーまたはセッションがlatin1文字セットを使用するように設定されている場合は使用する必要collate latin1_binがありますが、文字セットがutf8mb4使用されている場合は使用する必要がありますcollate utf8mb4_bin。したがって、最も堅牢なソリューションは、常に値を最も柔軟な文字セットに変換し、その文字セットにバイナリ照合を使用することです。

convertcollateを列ではなく値に適用するのはなぜですか?

比較を行う前に変換関数を列に適用すると、列にインデックスが存在する場合にクエリエンジンがインデックスを使用できなくなり、クエリが大幅に遅くなる可能性があります。したがって、可能な場合は常に値を変換する方が常に適切です。2つの文字列値の間で比較が実行され、そのうちの1つに明示的に指定された照合がある場合、クエリエンジンは、適用される値に関係なく、明示的な照合を使用します。

アクセント感度

MySqlは、_ci照合順序(通常はデフォルト)を使用する列の大文字と小文字を区別するだけでなく、アクセント記号も区別しないことに注意することが重要です。つまり'é' = 'e'。バイナリ照合(またはbinary演算子)を使用すると、文字列の比較でアクセントと大文字と小文字が区別されます。

なにutf8mb4

utf8MySQLでの文字セットはのための別名ですutf8mb3されている最近のバージョンで非推奨、それは(🐈のような文字列を符号化するために重要である)、4つのバイト文字をサポートしていないため。MySqlでUTF8文字エンコーディングを使用する場合は、utf8mb4文字セットを使用する必要があります。


8

以下は、MySQLバージョンが5.5以上の場合です。

/etc/mysql/my.cnfに追加します

  [mysqld]
  ...
  character-set-server=utf8
  collation-server=utf8_bin
  ...

私が試した他のすべての照合は大文字と小文字を区別しないようで、「utf8_bin」のみが機能しました。

この後、mysqlを再起動することを忘れないでください。

   sudo service mysql restart

http://dev.mysql.com/doc/refman/5.0/en/case-sensitiveivity.htmlによると、「latin1_bin」もあります。

「utf8_general_cs」は、mysqlの起動で受け入れられませんでした。(「_cs」を「大文字と小文字を区別する」と読みました-???)。


7

BINARYを使用して、このように大文字と小文字を区別することができます

select * from tb_app where BINARY android_package='com.Mtime';

残念ながら、このsqlはインデックスを使用できません。そのインデックスに依存するクエリでパフォーマンスヒットが発生します

mysql> explain select * from tb_app where BINARY android_package='com.Mtime';
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | tb_app | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1590351 |   100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+

幸いにも、私はこの問題を解決するためのいくつかのトリックを持っています

mysql> explain select * from tb_app where android_package='com.Mtime' and BINARY android_package='com.Mtime';
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
| id | select_type | table  | partitions | type | possible_keys             | key                       | key_len | ref   | rows | filtered | Extra                 |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
|  1 | SIMPLE      | tb_app | NULL       | ref  | idx_android_pkg           | idx_android_pkg           | 771     | const |    1 |   100.00 | Using index condition |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+  

これは、10.3.22 -MariaDB(libmysql-5.6.43を使用)では大文字と小文字が区別されないようです
user10398534

2

優れた!

パスワードを比較する関数のコードを共有します。

SET pSignal =
(SELECT DECODE(r.usignal,'YOURSTRINGKEY') FROM rsw_uds r WHERE r.uname =
in_usdname AND r.uvige = 1);

SET pSuccess =(SELECT in_usdsignal LIKE BINARY pSignal);

IF pSuccess = 1 THEN
      /*Your code if match*/
ELSE
      /*Your code if don't match*/

END IF;

declare pSuccess BINARY;最初に追加する必要があります
adinas

2

DBレベルで何も変更する必要はありません。SQLクエリを変更するだけで機能します。

例-

"SELECT * FROM <TABLE> where userId = '" + iv_userId + "' AND password = BINARY '" + iv_password + "'";

バイナリキーワードは大文字と小文字を区別します。


1

mysqlはデフォルトで大文字と小文字を区別しません。言語照合を次のように変更してみてください latin1_general_cs

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.