読者です 読者をやめる 読者になる 読者になる

(-> % read write unlearn)

All opinions expressed are solely my own and do not express the views or opinions of my employer.

MySQL 暗黙の型変換 intとcharの比較はintにキャストされる。

where句で以下の比較の結果にはまりました。。

mysql> select
    ->    '1' = '0'
    ->   ,'1' = 0
    ->   ,'A' = '0'
    ->   ,'A' = 0 -- これは真
    ->   ,'1' = '1'
    ->   ,'1' = 1
    ->   ,'1A' = '1'
    ->   ,'1A' = 1 -- ついでにこれも真
    -> ;
+-----------+---------+-----------+---------+-----------+---------+------------+----------+
| '1' = '0' | '1' = 0 | 'A' = '0' | 'A' = 0 | '1' = '1' | '1' = 1 | '1A' = '1' | '1A' = 1 |
+-----------+---------+-----------+---------+-----------+---------+------------+----------+
|         0 |       0 |         0 |       1 |         1 |       1 |          0 |        1 |
+-----------+---------+-----------+---------+-----------+---------+------------+----------+
1 row in set (0.00 sec)

理由は、以下の仕様で暗黙の型変換が起きているから。

mysql> select
    ->    cast('1' as signed)
    ->   ,cast('A' as signed)
    ->   ,cast('1A' as signed)
    ->   ,cast('1A2' as signed)
    -> ;
+---------------------+---------------------+----------------------+-----------------------+
| cast('1' as signed) | cast('A' as signed) | cast('1A' as signed) | cast('1A2' as signed) |
+---------------------+---------------------+----------------------+-----------------------+
|                   1 |                   0 |                    1 |                     1 |
+---------------------+---------------------+----------------------+-----------------------+
1 row in set, 3 warnings (0.00 sec)


1.charとintの比較はintに寄せる型変換が起こる。
2.charを前から一文字ずつintに変換していって、変換不能な場合は0と評価し、変換を終了する。
3.なので、'A' は 0 に変換され、結果'A' = 0 なんかは 0 = 0 になっちゃって「真」。

暗黙の型変換はSQL自体には仕様がないので、実装依存だそう。これはmysql4.1でやってます。Oracleでは、エラーにしてくれるとか。そっちのほうが潔い気が。