MySQLのchar,varcharは大文字小文字を区別しない

知ってる人には当たり前ですが、今更になってこれを知ったので書く。


# とりあえず検証用MySQLを作成

dockerでやる

```bash
docker run --name test-mysql -e MYSQL_ROOT_PASSWORD=passwd -d mysql:8.0
```

dockerコンテナに入る

```bash
docker exec -it test-mysql bash
```

MySQLクライアントに接続する

```bash
mysql -u root -p
```

データベースを作る

```sql
mysql> create database if not exists test_db;
Query OK, 1 row affected (0.01 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test_db            |
+--------------------+
5 rows in set (0.00 sec)

mysql> use test_db;
Database changed
```

とりあえずデフォルトの文字コードを確認する

```sql
mysql> select SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME from INFORMATION_SCHEMA.SCHEMATA where SCHEMA_NAME='test_db';
+-------------+----------------------------+------------------------+
| SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |
+-------------+----------------------------+------------------------+
| test_db     | utf8mb4                    | utf8mb4_0900_ai_ci     |
+-------------+----------------------------+------------------------+
```

# 検証用テーブルを作る

`varchar` と `varbinary`型のカラムを作る。
それぞれに
`test`, `Test`, `TEST`という文字列を入れました。

```sql
mysql> create table test (txt_varchar varchar(255), txt_varbinary varbinary(255));
Query OK, 0 rows affected (0.04 sec)

mysql> insert into test values ('test', 'test'), ('TEST', 'TEST'), ('Test', 'Test');
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0
```


# 大文字小文字が区別されない例

txt_varcharカラムに対して`test`で検索してみます。

```sql
mysql> select * from test where txt_varchar = 'test';
+-------------+------------------------------+
| txt_varchar | txt_varbinary                |
+-------------+------------------------------+
| test        | 0x74657374                   |
| TEST        | 0x54455354                   |
| Test        | 0x54657374                   |
+-------------+------------------------------+
3 rows in set (0.01 sec)
```
全部引っかかりました。

# 大文字小文字が区別される例

binary型で作成したtxt_varbinaryカラムに対して`test`で検索してみます。

```sql
mysql> select * from test where txt_varbinary = 'test';
+-------------+------------------------------+
| txt_varchar | txt_varbinary                |
+-------------+------------------------------+
| test        | 0x74657374                   |
+-------------+------------------------------+
1 row in set (0.01 sec)
```
無事、完全一致の文字列が検索されました。
ちなみにこれは解決方法ではなく、デフォルトのchar, varcharでは大文字小文字は区別されない例としてあげただけです。

# 解決方法

## BINARY演算子を使う

varchar型に対して検索をする際にBINARY演算子をつけると大文字小文字を区別して検索してくれます。

```sql
mysql> select * from test where txt_varchar = binary 'test';
+-------------+------------------------------+
| txt_varchar | txt_varbinary                |
+-------------+------------------------------+
| test        | 0x74657374                   |
+-------------+------------------------------+
1 row in set (0.00 sec)
```

## char, varcharに対してbinary属性をつける

binary属性を付与してみます。

```sql
mysql> alter table test modify txt_varchar varchar(255) binary;
Query OK, 0 rows affected, 1 warning (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 1
```

大文字小文字が区別されました。

```sql
mysql> select * from test where txt_varchar = 'test';
+-------------+------------------------------+
| txt_varchar | txt_varbinary                |
+-------------+------------------------------+
| test        | 0x74657374                   |
+-------------+------------------------------+
1 row in set (0.00 sec)
```

参考
[B.5.5.1 文字列検索での大文字/小文字の区別](https://dev.mysql.com/doc/refman/5.6/ja/case-sensitivity.html)