1、2、3…と続くデータ番号。データが削除されると1、3、4、5…のようにすきまができるのが普通です。通常は、このすきまを埋める必要はありませんが、番号が「座席番号」のような用途の場合、すきまを埋めたいこともあります。
たとえば、次のようなデータがあります。id列は連番を割り当てていますが、何件かのデータが削除されたことですきまができています。次に追加するidを「8」ではなく、すきまの先頭の「2」にしたい場合、どうすればよいでしょうか。
mysql> SELECT id, name FROM members6; +----+----------+ | id | name | +----+----------+ | 1 | 桜井洋子 | | 3 | 横山和弘 | | 4 | 金田由美 | | 5 | 山本正人 | | 7 | 斉藤高志 | +----+----------+ 5 rows in set (0.00 sec)
まず、テーブルを自己結合して、id列を並べてみます。自己結合とは、1つのテーブルを“1人2役”のように使い、同じテーブルを結合する操作です。
mysql> SELECT a.id, b.id
-> FROM members6 a LEFT OUTER JOIN members6 b
-> ON a.id = b.id;
+----+------+
| id | id |
+----+------+
| 1 | 1 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 7 | 7 |
+----+------+
5 rows in set (0.01 sec)
上の例ではid列が同じ値同士を結合しましたが、今度は、1つ番号をずらして結合してみます。つまり、左側のid=1の行は右側のid=2の行、左側のid=2の行は右側のid=3の行と結合します。それには、ON句を変更して、左側のテーブルのid列に1を加算した値と結合します。
mysql> SELECT a.id, b.id AS next_id
-> FROM members6 a LEFT OUTER JOIN members6 b
-> ON a.id + 1 = b.id;
+----+---------+
| id | next_id |
+----+---------+
| 1 | NULL |
| 3 | 4 |
| 4 | 5 |
| 5 | NULL |
| 7 | NULL |
+----+---------+
5 rows in set (0.00 sec)
すると、next_idがNULLになるデータが発生します。これは、「自分のid + 1」というデータが存在しないことを示しています。つまり、「1」の次の「2」が存在せず、また、「5」の次の「6」が存在しないのです。この結果から、「2」と「6」が欠けていることがわかります。
next_idがNULLのデータ(b.id IS NULL)の中から、最も小さい「1」に1を加算した「2」を取得すれば、次のデータに割り当てる「すきま」を取得することができます。SQL文は次のとおりです。
mysql> SELECT MIN(a.id) + 1
-> FROM members6 a LEFT OUTER JOIN members6 b
-> ON a.id + 1 = b.id
-> WHERE b.id IS NULL;
+---------------+
| MIN(a.id) + 1 |
+---------------+
| 2 |
+---------------+
1 row in set (0.00 sec)
この値をINSERT文に反映すれば、連番のすきまをうめていくことができます。次の例ではid列に「2」が割り当てられています。
mysql> INSERT INTO members6(id, name, age)
-> SELECT MIN(a.id) + 1, '佐藤史郎', 29
-> FROM members6 a LEFT OUTER JOIN members6 b
-> ON a.id + 1 = b.id
-> WHERE b.id IS NULL;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT id, name FROM members6 ORDER BY id;
+----+----------+
| id | name |
+----+----------+
| 1 | 桜井洋子 |
| 2 | 佐藤史郎 |
| 3 | 横山和弘 |
| 4 | 金田由美 |
| 5 | 山本正人 |
| 7 | 斉藤高志 |
+----+----------+
6 rows in set (0.00 sec)
(西沢直木著:『SQL逆引きレシピ (PROGRAMMER’S RECiPE)』より)
