MySQL InnoDBで複数レコードを挿入してそれらのid(AUTO INCREMENT)を取得する方法

InnoDBで複数のレコードをテーブルに挿入したときに、それらのレコードにAUTO INCREMENTで割り振られたidの一覧を取得する方法を調べてみました。

## 挿入するレコードが1件の場合
挿入するレコードが1件の場合は`LAST_INSERT_ID`関数を使って挿入したデータのidを取得できます。

```sql
mysql> CREATE TABLE t (
    ->   id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
    ->   name VARCHAR(10) NOT NULL
    -> );
Query OK, 0 rows affected (0.09 sec)

mysql> INSERT INTO t VALUES (NULL, 'Bob');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
|  1 | Bob  |
+----+------+
1 row in set (0.01 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                1 |
+------------------+
1 row in set (0.00 sec)
```

## 複数件の場合
複数件の場合にも`LAST_INSERT_ID`を使えば取得できそうですが、全部のidは取得できず、*最初の1件分のidだけ*取得できます。

```sql
mysql> INSERT INTO t VALUES
    -> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
|  1 | Bob  |
|  2 | Mary |
|  3 | Jane |
|  4 | Lisa |
+----+------+
4 rows in set (0.01 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)
```

1番目に挿入したレコードのidはわかるので、あとは挿入した件数を取得できれば計算で全部のidを出すことができそうです。
`ROW_COUNT`関数を使うことで挿入した件数を取得できます。

```sql
mysql> INSERT INTO t VALUES(1),(2),(3);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT ROW_COUNT();
+-------------+
| ROW_COUNT() |
+-------------+
|           3 |
+-------------+
1 row in set (0.00 sec)
```

`LAST_INSERT_ID`と`ROW_COUNT`を組み合わせることで振られたidを計算で出すことができます。

複数レコード挿入の場合にそれらのidが連続で振られないと上記のロジックで計算できないのですが、MySQLの*自動インクリメントロックモード*で連続性を保証することができます。

> innodb_autoinc_lock_mode が 0 (「従来」) または 1 (「連続」) に設定されている場合、テーブルレベル AUTO-INC ロックがステートメントの終了まで保持され、同時に実行できるステートメントはこのような 1 つのステートメントだけであるため、任意のステートメントによって生成される自動インクリメント値は、ギャップのない連続的なものとなります。

## まとめ
### 前提
* innodb_autoinc_lock_modeが0または1に設定されている

### 方法
`LAST_INSERT_ID`と`ROW_COUNT`関数を使う。
(`LAST_INSERT_ID`の値) 〜 (`LAST_INSERT_ID`の値 + `ROW_COUNT`の値 - 1)が目的のidになる。

```sql
mysql> INSERT INTO t VALUES (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT LAST_INSERT_ID() as first, ROW_COUNT() as count;
+-------+-------+
| first | count |
+-------+-------+
|     2 |     3 |
+-------+-------+
1 row in set (0.00 sec)

mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
|  1 | Bob  |
|  2 | Mary |
|  3 | Jane |
|  4 | Lisa |
+----+------+
4 rows in set (0.00 sec)
```
上記の例の場合、`first`〜`first + count - 1`で2〜4が今回挿入したレコードのidになります。

※ 上記の前提が守られていない場合には他の方法で頑張るしかなさそうです。
[[MySQL] INSERTしたデータのIDを取得したい](http://jumble-note.blogspot.jp/2013/06/mysql-insertid.html)


## 参考文献
* [How can I Insert many rows into a MySQL table and return the new IDs?
](https://stackoverflow.com/questions/7333524/how-can-i-insert-many-rows-into-a-mysql-table-and-return-the-new-ids)
* [情報関数](https://dev.mysql.com/doc/refman/5.6/ja/information-functions.html)
* [構成可能な InnoDB の自動インクリメントロック](https://dev.mysql.com/doc/refman/5.6/ja/innodb-auto-increment-configurable.html)