MySQL で後からユニークインデックスを追加するには

February 9, 2008

フィールドを Unique にする方法

mysql> alter table 対象テーブル add unique (対象フィールド);

作業ログ(フィールドサイズが 999 バイトを超えていたら)

今回 support テーブルの uri フィールドをユニーク化しようとしたが、

1
2
mysql> alter table support add unique (uri);
ERROR 1071 (42000): Specified key was too long; max key length is 999 bytes

となってしまった。定義を調べると、

1
2
3
4
5
6
7
8
9
10
mysql> show fields from support;
+---------+---------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| uri | varchar(512) | NO | MUL | | |
| title | varchar(1024) | NO | MUL | | |
| content | mediumtext | YES | | NULL | |
| updated | timestamp | NO | | CURRENT_TIMESTAMP | |
+---------+---------------+------+-----+-------------------+----------------+

512だが、UTF-8なので超えてしまっているのだろう。
実際には数文字しか入っていないので別のフィールド uri2 を作って、そこに値をコピーしてからユニーク化して、元の列を削除してリネームすることにした。
127なら4倍しても999バイトには届かないので、varchar(127) で定義する。

1
2
3
mysql> alter table support add column uri2 varchar(127);
Query OK, 20799 rows affected (1 min 0.37 sec)
Records: 20799 Duplicates: 0 Warnings: 0

uri フィールドから uri2 フィールドに値をコピーする。

1
2
3
mysql> update support set uri2 = uri;
Query OK, 20799 rows affected (6 min 30.64 sec)
Rows matched: 20799 Changed: 20799 Warnings: 0

uri フィールドを削除する。

1
2
3
mysql> alter table support drop uri;
Query OK, 20799 rows affected (1 min 0.60 sec)
Records: 20799 Duplicates: 0 Warnings: 0

uri2 フィールドをユニークにする。

1
2
3
mysql> alter table support add unique (uri2);
Query OK, 20799 rows affected (1 min 1.66 sec)
Records: 20799 Duplicates: 0 Warnings: 0

uri2 から uri フィールド名を変更する(id フィールドの後ろに移す)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> alter table support change column \`uri2\` \`uri\` varchar(127) after id;
Query OK, 20799 rows affected (1 min 0.41 sec)
Records: 20799 Duplicates: 0 Warnings: 0
mysql> show fields from support;
+---------+---------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| uri | varchar(127) | YES | UNI | NULL | |
| title | varchar(1024) | NO | MUL | | |
| content | mediumtext | YES | | NULL | |
| updated | timestamp | NO | | CURRENT_TIMESTAMP | |
+---------+---------------+------+-----+-------------------+----------------+
5 rows in set (0.00 sec)

実は列名を変更するときに定義も変更できる(というか指定する)ことに気づいた。
ということで本当は、

1
2
mysql> alter table support change column \`uri\` \`uri\` varchar(127);
mysql> alter table support add unique (uri);

だけでいけたかもしれない。

tilfin freelance software engineer