[MySQL]数字文字列を正しくソートする
2024/05/21
MySQLで数字文字列を数値順に正しくソートする方法のメモです。

やり方
例として、連番IDとアルファベット文字を格納するようなテーブルを作成します。
id列に連番を、value列に各アルファベット文字が順番になるようにレコードを追加します。

mysql> CREATE TABLE alphabet (id varchar(2) NOT NULL, value char(1) NOT NULL, PRIMARY KEY(id));
Query OK, 0 rows affected (0.10 sec)
mysql>
mysql> insert into alphabet values
    -> ('1','A'),
    -> ('2','B'),
    -> ('3','C'),
    -> ('4','D'),
    -> ('5','E'),
    -> ('6','F'),
    -> ('7','G'),
    -> ('8','H'),
    -> ('9','I'),
    -> ('10','J'),
    -> ('11','K'),
    -> ('12','L'),
    -> ('13','M'),
    -> ('14','N'),
    -> ('15','O'),
    -> ('16','P'),
    -> ('17','Q'),
    -> ('18','R'),
    -> ('19','S'),
    -> ('20','T'),
    -> ('21','U'),
    -> ('22','V'),
    -> ('23','W'),
    -> ('24','X'),
    -> ('25','Y'),
    -> ('26','Z');
Query OK, 26 rows affected (0.04 sec)
Records: 26 Duplicates: 0 Warnings: 0

1〜26までの連番とアルファベットの各文字が順番に紐づいたレコードが作成されました。
これをORDER BY句でソートして全件取得します。

mysql> SELECT * FROM alphabet OEDER BY id;
+----+-------+
| id | value |
+----+-------+
| 1 | A |
| 10 | J |
| 11 | K |
| 12 | L |
| 13 | M |
| 14 | N |
| 15 | O |
| 16 | P |
| 17 | Q |
| 18 | R |
| 19 | S |
| 2 | B |
| 20 | T |
| 21 | U |
| 22 | V |
| 23 | W |
| 24 | X |
| 25 | Y |
| 26 | Z |
| 3 | C |
| 4 | D |
| 5 | E |
| 6 | F |
| 7 | G |
| 8 | H |
| 9 | I |
+----+-------+
26 rows in set (0.00 sec)

なんか思ったとおりの順番にソートされませんでした。

id列のデータ型を文字列で定義してしまったので、文字コードに則ってソートされてしまいました。
なので、数値に変換した上でソートしなければいけません。

CAST関数を利用して、文字列で定義したid列を整数値に変換して、再びORDER BY句でソートします。

mysql> SELECT * FROM alphabet OEDER BY CAST(id as signed);
+----+-------+
| id | value |
+----+-------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | E |
| 6 | F |
| 7 | G |
| 8 | H |
| 9 | I |
| 10 | J |
| 11 | K |
| 12 | L |
| 13 | M |
| 14 | N |
| 15 | O |
| 16 | P |
| 17 | Q |
| 18 | R |
| 19 | S |
| 20 | T |
| 21 | U |
| 22 | V |
| 23 | W |
| 24 | X |
| 25 | Y |
| 26 | Z |
+----+-------+
26 rows in set (0.04 sec)

順番通りにソートできました。

さいごに
文字列から数値に変換できるから問題ないと思うかもしれないけど、そもそも連番で採番するような列は数値型で定義しましょう。
本来であれば、設計段階でしっかりと運用値に合わせた型定義をして、こんなことが起きないようにするべきです。
数値型であればAUTO_INCREMENT属性を付与することで連番を自動で採番もできます。

DB設計はしっかりやりましょう。

参考サイト
https://dev.mysql.com/doc/refman/8.0/ja/cast-functions.html