LAST_INSERT_ID()

LAST_INSERT_ID(), LAST_INSERT_ID(expr)

MySQL 5.1.12 以降では、LAST_INSERT_ID() ( 引数なし ) は、最も最近に実行された INSERT 文の結果として AUTO_INCREMENT カラムに正常に インサートされた、自動的に生成された最初の値を戻します。LAST_INSERT_ID() の値は、正常にインサートされた行がない場合は、未変更のままになります。

例えば、AUTO_INCREMENT 値を生成する行をインサートした後は、次のようにして値を得ることができます :

mysql> SELECT LAST_INSERT_ID();
        -> 195

MySQL 5.1.11 以前では、LAST_INSERT_ID() ( 引数なし ) は、行が正常にインサート、または更新された場合、自動低に生成された最初の値を戻します。つまり、戻された値は、テーブルに正常にインサートされなかった値である可能性があります。正常にインサートされた行がなければ、LAST_INSERT_ID() は 0 を戻します。

LAST_INSERT_ID() の値は、INSERT または UPDATE 文のすべての行が正常である場合、全バージョンにわたって一貫するでしょう。

実行中のステートメントが、LAST_INSERT_ID() の値に影響をおよぼすことはありません。ひとつのステートメントで AUTO_INCREMENT 値を生成し、その後、独自の AUTO_INCREMENT カラムで行をテーブルにインサートする複数行の INSERT 文で、LAST_INSERT_ID() を照会すると仮定します。LAST_INSERT_ID() の値は 2 番目のステートメントに安定したまま残ります。2 番目以降の行でのその値は、以前の行の挿入に影響されません。( しかし、LAST_INSERT_ID()LAST_INSERT_ID(expr) への参照を混ぜると、その効果は未定義になります ) 。

以前のステートメントがエラーを戻した場合、LAST_INSERT_ID() は未定義になります。トランザクション テーブルでは、ステートメントがエラーによってロールバックされる場合、LAST_INSERT_ID() は未定義のまま残されます。手動の ROLLBACK では、LAST_INSERT_ID() の値はトランザクションの前に復元されず、ROLLBACK 時点と同じまま残ります。

ストアド ルーチン ( プロシージャまたは関数 ) もしくはトリガのボディ内で、LAST_INSERT_ID() の値は、これらの種類のオブジェクトの外で実行されたステートメントと同様に変化します。後に続くステートメントに参照される LAST_INSERT_ID() の値に基づくストアド ルーチンもしくはトリガの効果は、ルーチンの種類によって異なります :

  • ストアド プロシージャが LAST_INSERT_ID() の値を変えるステートメントを実行する場合、変更された値はプロシージャ呼び出しに従うステートメントによって参照されます。

  • 値を変更するストアド ファンクションやトリガでは、値は関数やトリガが終了した時に復元され、続くステートメントは変更された値を参照しません。

生成された ID は、接続ベースで サーバ内で保持されます。つまり、関数によって指定のクライアントに戻された値は、そのクライアントによって AUTO_INCREMENT カラムに影響を及ぼす最も最近のステートメントのために生成された、最初の AUTO_INCREMENT 値です。この値は、他のクライアントが独自の AUTO_INCREMENT 値を生成した場合でも、他のクライアントによって影響を受けることはありません。この動作は、各クライアントが他のクライアントの動向を気にせず、ロックやトランザクションなしで、独自の ID を呼び出せるようにします。

行の AUTO_INCREMENT カラムを 非 「magic」 値 ( NULL でも 0 でもない値 ) に設定する場合、LAST_INSERT_ID() の値は変更されません。

重要点 : 単一の INSERT 文を使用して複数の行をインサートする場合、LAST_INSERT_ID() は、最初の インサートされた行のみに対して生成された値を戻します。これは、他のサーバに対して同じ INSERT 文を簡単に再現できるようにするためです。

例 :

mysql> USE test;
Database changed
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)

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)

2 番目の INSERT 文が 3 つの新しい行を t にインサートしても、これらの行の 1 番目に生成された ID は 2 であり、次の SELECT 文に対して LAST_INSERT_ID() が返す値も同じです。

INSERT IGNORE を使用して行を無視する場合は、AUTO_INCREMENT カウンタは増分されず、行がインサートされなかったことを反映して、LAST_INSERT_ID()0 を戻します。

exprLAST_INSERT_ID() への引数として与えられる場合、その引数の値は関数によって戻され、LAST_INSERT_ID() によって戻される次の値として記憶されます。これによってシークエンスのシミュレーションをすることも可能です :

  1. テーブルを作成してシークエンス カウンタを保留にし、初期化 :

    mysql> CREATE TABLE sequence (id INT NOT NULL);
    mysql> INSERT INTO sequence VALUES (0);
  2. テーブルを使用して、次のようにシークエンス番号を生成 :

    mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
    mysql> SELECT LAST_INSERT_ID();

    UPDATE 文はシークエンス カウンタを増分し、LAST_INSERT_ID() への次の呼び出しが更新された値を戻すようにします。SELECT 文はその値を引き出します。mysql_insert_id() C API 関数は、値の入手に使用することもできます。詳細は 項23.2.3.37. 「mysql_insert_id()」 を参照してください。

LAST_INSERT_ID() を呼び出さずにシークエンスを生成することはできますが、このように関数を使用することの利点は、ID 値が自動的に生成された最後の値として保持されることです。独自のシークエンス値を生成する他のクライアントと互いに影響しあうことなく、複数のクライアントが UPDATE 文を発行し、UPDATE 文 ( または mysql_insert_id() ) でそれぞれのシークエンス値を取得することができるため、マルチユーザでも安全です。

mysql_insert_id()INSERT および UPDATE 文の後にのみ更新され、SELECT もしくは SET のような他の SQL 文を実行した後に、C API 関数を使用して LAST_INSERT_ID(expr) の値を引き出すことはできないのでご注意ください。