MySQLと「令和」

新元号が「令和」に決まったことなので、MySQLでの扱いについての話を。

普通の文字

「令」も「和」もJIS第一水準に含まれている基本的な文字なので普通に日本語が使用できるcharsetで使用できます。

mysql> create table t (
  utf8mb4 varchar(255) charset utf8mb4,
  utf8mb3 varchar(255) charset utf8mb3,
  utf16 varchar(255) charset utf16,
  utf32 varchar(255) charset utf32,
  cp932 varchar(255) charset cp932,
  eucjpms varchar(255) charset eucjpms,
  sjis varchar(255) charset sjis,
  ujis varchar(255) charset ujis
);

mysql> insert into t values ('令和', '令和', '令和', '令和', '令和', '令和', '令和', '令和');

mysql> select * from t\G
*************************** 1. row ***************************
utf8mb4: 令和
utf8mb3: 令和
  utf16: 令和
  utf32: 令和
  cp932: 令和
eucjpms: 令和
   sjis: 令和
   ujis: 令和

mysql> select hex(utf8mb4), hex(utf8mb3), hex(utf16), hex(utf32), hex(cp932), hex(eucjpms), hex(sjis), hex(ujis) from t\G
*************************** 1. row ***************************
hex(utf8mb4): E4BBA4E5928C
hex(utf8mb3): E4BBA4E5928C
  hex(utf16): 4EE4548C
  hex(utf32): 00004EE40000548C
  hex(cp932): 97DF9861
hex(eucjpms): CEE1CFC2
   hex(sjis): 97DF9861
   hex(ujis): CEE1CFC2

なんの問題もないですね。

「令」と「令」

ところで、ユニコードには「令」と見た目が同じ字が他にもあると話題になりました。 普通の「令」は U+4EE4(UTF-8 で E4BBA4)、もうひとつの「令」は U+F9A8(UTF-8 で EFA6A8)です。

mysql> set @4ee4=_utf8mb4 0xE4BBA4E5928C, @f9a8=_utf8mb4 0xEFA6A8E5928C;

mysql> select @4ee4, @f9a8;
+--------+--------+
| @4ee4  | @f9a8  |
+--------+--------+
| 令和   | 令和   |
+--------+--------+

見た目が同じなのにコードが違うから何かトラブルが起きるんじゃないかと言われたりしてますが、実際にはこのような文字は他にもあるので、今まで問題になったことがないんならそんなに問題にならないんじゃないですかね。

ところで MySQL では、この二文字は = で比較すると一致として扱われます。LIKE では不一致です。

mysql> select @4ee4, @f9a8, @4ee4=@f9a8, @4ee4 LIKE @f9a8;
+--------+--------+-------------+------------------+
| @4ee4  | @f9a8  | @4ee4=@f9a8 | @4ee4 LIKE @f9a8 |
+--------+--------+-------------+------------------+
| 令和   | 令和   |           1 |                0 |
+--------+--------+-------------+------------------+

理由は調べてませんが、たぶん = は正規化して比較するけど LIKE は正規化しないで比較するみたいな感じなんじゃないかと思います(字面的には =LIKE が逆のような印象で面白い)。

異体字セレクタ

もうひとつ「令」と言えば異体字ですよね。ユニコードでは異体字セレクタというコードを後ろにつけることで字体を選択することができます。

環境によりますが「U+4EE4 U+E0102」の文字「令󠄂」は下が「マ」のように見えるコードです。

異体字セレクタを使用した場合も、= で一致し LIKE では不一致となります。

mysql> set @4ee4_e0102=_utf8mb4 0xE4BBA4F3A08482E5928C;

mysql> select @4ee4, @4ee4_e0102, @4ee4=@4ee4_e0102, @4ee4 LIKE @4ee4_e0102;
+--------+-------------+-------------------+------------------------+
| @4ee4  | @4ee4_e0102 | @4ee4=@4ee4_e0102 | @4ee4 LIKE @4ee4_e0102 |
+--------+-------------+-------------------+------------------------+
| 令和   | 令󠄂和        |                 1 |                      0 |
+--------+-------------+-------------------+------------------------+

合字

そして元号と言えば合字ですよね。

「明治」「大正」「昭和」「平成」には、それぞれ1文字で表せる「㍾」「㍽」「㍼」「㍻」という文字があります。 「令和」にも「㋿」(U+32FF)という文字が割り当てられています(見えないかもしれないけどOSやフォントが対応すればちゃんと見えるようになるはず)。

合字も正規化して比較されるので「平成」と「㍻」は一致するのですが、「令和」とU+32FFは一致しません。

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

U+32FF が「令和」の合字となるのはUnicodeのバージョン12.1からです。Unicode 12.1はどうやら日本の新元号に対応した合字を含めるためだけに作られるバージョンらしいです。迷惑な話ですね。2019/5/7 にリリースされるようです。

Unicode 12.1までは U+32FF は何の文字でもないコードです。

MySQL 8.0 のUnicodeのバージョンは9.0なので対応してないのですね。MySQL がいつUnicode 12.1に対応するのかはわかりませんが。


という感じですが、まあ、実際にはそんなに問題になることはないんじゃないですかね。

[追記] 続きを書きました https://tmtms.hatenablog.com/entry/201904/mysql-reiwa2