この記事について

Python + MySQL でAPIの開発をしていました。

日本語(半角全角含)と英数記号が格納されているVarChar型カラムに対して、SELECTI結果をUnicodeの昇順で取得しようとしました。 ORDER BY ASCを使用して実行しましが、文字コード順ではなくかといって50順でもない順序で結果を取得してしまいました。

なぜORDER BY 句で文字コード昇順できなかったのか?どうやって解決したのかについて書きたいと思います。

MySQL のバージョン

  • 8.0.26

起きていたこと

VarChar型カラムに対して文字コード昇順で ORDER BY ASC句で昇順で取得するために実行しました。

SELECT name FROM name_table ORDER BY name ASC

UTF8 の文字コードを確認します・・・が、パッと見文字コードとは関係がない順序で結果を取得していました。(数値は0-1で並んでいますが)

index(SELECT結果順) name UTF8
1 .akari \2E\61\6B\61\72\69
2 ‘;kudo \27\3B\6B\75\64\6F
3 010 \30\31\30
4 010 \EFBC90\EFBC91\EFBC90
5 111 \31\31\31
6 111 \EFBC91\EFBC91\EFBC91
7 くどう \E3818F\E381A9\E38186
8 クドウ \EFBDB8\EFBE84\EFBE9E\EFBDB3
9 はる \E381AF\E3828B
10 ぱる \E381B1\E3828B
11 ばる \E381B0\E3828B

原因と解決策

MySQLでの照合順序(COLLATE)が原因でした。
VarChar型カラムの Character Set : utf8mb4 のデフォルトの照合順序は utf8mb4_0900_ai_ci が適用されるためUnicode順ではなく utf8mb4_0900_ai_ciになるように結果が返って来ていました。
そのため、Unicode順になるように照合順序を適用させる必要がありました。
ですので解決策としてCOLLATE句を使用してUnicode順の照合順序であるutf8mb4_bin を使用します。

SELECT name FROM name_table ORDER BY name ASC COLLATE utf8mb4_bin
index(SELECT結果順) name UTF8
1 ‘;kudo \27\3B\6B\75\64\6F
2 .akari \2E\61\6B\61\72\69
3 010 \30\31\30
4 111 \31\31\31
5 くどう \E3818F\E381A9\E38186
6 はる \E381AF\E3828B
7 ばる \E381B0\E3828B
8 ぱる \E381B1\E3828B
9 010 \EFBC90\EFBC91\EFBC90
10 111 \EFBC91\EFBC91\EFBC91
11 クドウ \EFBDB8\EFBE84\EFBE9E\EFBDB3

UTF8 の文字コードを確認して、無事にUnicode順で結果を得ることができました。

参考

余談

他DBでの照号順序に関して。
今回の件はMySQLでの照合順序で、他DBでは設定が違うのでDBによって気にしなければならないかと思います。

最後に

VarChar型カラムの Character Set の確認を見逃しており、解決するために頭を捻りました。SQLを叩いて並び替えが予想と違うときは照合順序を確認して調べてみるのも1つの手段なのだと勉強になりました。

悩んでいる方の参考になれば幸いです。