MySQLと令和

とみたまさひろ

2019-12-18

ニフクラエンジニアミートアップ
#nifcloud_emup

自己紹介

令和元年もそろそろ終わりですね

今日は「令和」の話をします

令和になってからこの話をするのは5回目くらいなのでどこかで見たことあるという人は生暖かい目で見てください

その1

「令和」と言えば…

似てるけど違う文字

「令」と「令」

同じに見えるけど別の文字

  • 「令」 U+4EE4 CJK UNIFIED IDEOGRAPH
  • 「令」 U+F9A8 CJK COMPATIBILITY IDEOGRAPH

困る!

MySQLでは

mysql> set @a='令和', @b='令和';
mysql> select @a, @b, hex(@a), hex(@b);
+--------+--------+--------------+--------------+
| @a     | @b     | hex(@a)      | hex(@b)      |
+--------+--------+--------------+--------------+
| 令和   | 令和   | E4BBA4E5928C | EFA6A8E5928C |
+--------+--------+--------------+--------------+
mysql> select @a=@b;
+-------+
| @a=@b |
+-------+
|     1 | ← ❗❗
+-------+

一致

😊

良かったですね

その2

「令和」と言えば…

異体字

令󠄁」と「令󠄂

違う字形だけど同じ文字

異体字セレクタ

  • 」 U+4EE4
  • 令󠄁」 U+4EE4 U+E0101
  • 令󠄂」 U+4EE4 U+E0102

困る!

MySQLでは

mysql> set @a='令和', @b='令󠄁和', @c='令󠄂和';
mysql> select hex(@a), hex(@b), hex(@c)\G
*************************** 1. row ***************************
hex(@a): E4BBA4E5928C
hex(@b): E4BBA4F3A08481E5928C
hex(@c): E4BBA4F3A08482E5928C
mysql> select @a=@b, @b=@c;
+-------+-------+
| @a=@b | @b=@c |
+-------+-------+
|     1 |     1 | ← ❗❗
+-------+-------+

※都合により同じ字体に見えてます

一致

😊

良かったですね

その3

「令和」と言えば…

元号

元号と言えば…

合字

明治(U+660E U+6CBB) ㍾(U+337E)
大正(U+5927 U+6B63) ㍽(U+337D)
昭和(U+662D U+548C) ㍼(U+337C)
平成(U+5E73 U+6210) ㍻(U+337B)
令和(U+4EE4 U+548C) ㋿(U+32FF)

MySQLでは

mysql> select '明治'='㍾', '大正'='㍽', '昭和'='㍼',
    -> '平成'='㍻', '令和'='㋿'\G
*************************** 1. row ***************************
'明治'='㍾': 1   ← 一致❗
'大正'='㍽': 1   ← 一致❗
'昭和'='㍼': 1   ← 一致❗
'平成'='㍻': 1   ← 一致❗
'令和'='㋿': 0   ← 不一致❗

😇

残念

なにが起きてるのか?

MySQL は Unicode 9.0.0 準拠

Unicodeの照合順序

文字毎にWeightという値が定義されている
Weightが等しいなら等しい文字

Unicode Collation Algorithm (UCA)
https://unicode.org/reports/tr10/tr10-34.html

Default Unicode Collation Element Table (DUCET)
https://www.unicode.org/Public/UCA/9.0.0/allkeys.txt
↑計算で求められない文字ごとの値

その1

似てるけど違う文字

「令」と「令」

  • 「令」 U+4EE4 CJK UNIFIED IDEOGRAPH
    DUCETには無いけど計算で求まる
    [.FB40.0020.0002][.(CP | 0x8000).0000.0000]
    → [.FB40.0020.0002][.CEE4.0000.0000]
    
  • 「令」 U+F9A8 CJK COMPATIBILITY IDEOGRAPH
    DUCETにある
    F9A8  ; [.FB40.0020.0002][.CEE4.0000.0000]
    

Weightが一致するから等しい

その2

異体字

令󠄁」と「令󠄂

異体字セレクタ

  • 」 U+4EE4
  • 令󠄁」 U+4EE4 U+E0101
  • 令󠄂」 U+4EE4 U+E0102

異体字セレクタはDUCETにある

E0101 ; [.0000.0000.0000] # VARIATION SELECTOR-18
E0102 ; [.0000.0000.0000] # VARIATION SELECTOR-19

UCAではすべてゼロの文字は無視して比較
→ 一致

その3

合字

㍾ / ㍽ / ㍼ / ㍻ / ㋿

平成=㍻

  • 平成(U+5E73 U+6210): ㍻(U+337B)
平成 [.FB40.0020.0002][.DE73.0000.0000][.FB40.0020.0002][.E210.0000.0000]
㍻   [.FB40.0020.001C][.DE73.0000.0000][.FB40.0020.001C][.E210.0000.0000]

ちょっと違う… 🤔

utf8mb4_0900_ai_ci

MySQLのデフォルトのCollation

要素 意味
utf8mb4 4バイトUTF-8
0900 Unicode 9.0.0
ai アクセントの違いを無視
ci 大文字小文字の違いを無視

ciの場合はWeightの3番目を無視

ciの場合はWeightの3番目を無視

平成 [.FB40.0020.0002][.DE73.0000.0000][.FB40.0020.0002][.E210.0000.0000]
㍻   [.FB40.0020.001C][.DE73.0000.0000][.FB40.0020.001C][.E210.0000.0000]

3番目を無視すると

平成 [.FB40.0020.    ][.DE73.0000.    ][.FB40.0020.    ][.E210.0000.    ]
㍻   [.FB40.0020.    ][.DE73.0000.    ][.FB40.0020.    ][.E210.0000.    ]

一致

令和≠㋿

そもそも「㋿」がDUCETに無い!

「㋿」はUnicode 9.0.0 に無い!

「㋿」はUnicode 12.1.0 で追加

http://unicode.org/versions/Unicode12.1.0/

12.1 は「㋿」のためだけに 5/7 にリリース

Unicode 12.1 adds exactly one character, for a total of 137,929 characters.
The new character added to Version 12.1 is:
  U+32FF SQUARE ERA NAME REIWA
Version 12.1 adds that single character to enable software to be rapidly updated to support the new Japanese era name in calendrical systems and date formatting. The new Japanese era name was officially announced on April 1, 2019, and is effective as of May 1, 2019.

MySQL の Unicode 12.1 対応はいつだろう… 🤔

「令和」に関するあれこれは
MySQL独自の変な挙動じゃなくてUnicodeの規則だった!

Unicode規則にちゃんと従ってるMySQLえらい!

Collationについて学べる「令和」すごい!

おまけ

日本語Collation

utf8mb4_ja_0900_as_cs

utf8mb4_ja_0900_as_cs_ks

要素 意味
utf8mb4 4バイトUTF-8
ja 言語
0900 Unicode 9.0.0
as アクセント違いは別の文字
cs 大文字小文字は別の文字
ks 平仮名と片仮名は別の文字

JIS規則のCollation

比較 ai_ci as_ci as_cs ja as_cs ja as_cs_ks bin
A=a × × × ×
A= × ×
= × × × ×
= × × × ×
= × × ×
== × × × × ×
1= × × × ×
= × × ×
=令󠄂 ×
平成= × × × ×

ソート順もJIS

mysql> select c,hex(c) from t order by c collate utf8mb4_0900_as_cs;
+------+--------+
| c    | hex(c) |
+------+--------+
| 亜   | E4BA9C |
| 伊   | E4BC8A |
| 奥   | E5A5A5 |
| 宇   | E5AE87 |
| 栄   | E6A084 |
+------+--------+

mysql> select c,hex(c) from t order by c collate utf8mb4_ja_0900_as_cs;
+------+--------+
| c    | hex(c) |
+------+--------+
| 亜   | E4BA9C |
| 伊   | E4BC8A |
| 宇   | E5AE87 |
| 栄   | E6A084 |
| 奥   | E5A5A5 |
+------+--------+

長音記号のソート順は前の文字の母音と同じ

mysql> select c from t2 order by c collate utf8mb4_ja_0900_as_cs;
+--------+
| c      |
+--------+
| かー   |
| かあ   |
| かい   |
| きあ   |
| きー   |
| きい   |
| くあ   |
| くい   |
| くー   |
+--------+

業界によってはうれしいかも

ちょっとやりすぎ感?

文句はJISに

おわり