オフィス狛 技術部のJoeです。
INSERT後にAUTO INCREMENTで自動採番された値を使用したいことがあるかと思いますが、
MySQLでは前回INSERTのAUTO INCREMENT値を「LAST_INSERT_ID()」関数で取得できます。
テーブルを作成して、1件INSERTすると「1」が取れました。
mysql> CREATE TABLE test ( -> id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, -> name VARCHAR(10) NOT NULL ); mysql> INSERT INTO test ( name ) VALUES ( '111' ); mysql> SELECT LAST_INSERT_ID(); +------------------+ | LAST_INSERT_ID() | +------------------+ | 1 | +------------------+
AUTO INCREMENTは一意であることを保証してくれますので、各セッション内で最後にINSERTした値が取れました。
【セッションA】INSERT INTO test ( name ) VALUES ( '111' ); 【セッションB】INSERT INTO test ( name ) VALUES ( '222' ); 【セッションB】SELECT LAST_INSERT_ID(); +------------------+ | LAST_INSERT_ID() | +------------------+ | 2 | +------------------+ 【セッションA】SELECT LAST_INSERT_ID(); +------------------+ | LAST_INSERT_ID() | +------------------+ | 1 | +------------------+
と、便利な関数ですが、想定する値が取れないパターンも併せてをご紹介します。
●AUTO INCREMENTのカラムに値を指定してINSERTした場合
値を指定してしまうと取得できません。同一セッションで前回自動採番された値が取れるようです。
mysql> INSERT INTO test ( name ) VALUES ( '111' ); -- 値を指定しない(自動採番) mysql> INSERT INTO test ( id, name ) VALUES ( 10, '222' ); -- 値を指定する mysql> SELECT LAST_INSERT_ID(); +------------------+ | LAST_INSERT_ID() | +------------------+ | 1 | +------------------+
●単一のINSERT文で複数データをINSERTした場合
3件INSERTしたので「3」が欲しいのですが、「1」が取れました。
mysql> INSERT INTO test ( name ) VALUES ( '111' ), ( '222' ), ( '333' ); mysql> SELECT LAST_INSERT_ID(); +------------------+ | LAST_INSERT_ID() | +------------------+ | 1 | +------------------+
●別セッションの場合
「当然!」と言われそうですが、別セッションでは取得できません。
下記のようなDB接続から開始するAUTO INCREMENT値の取得処理みたいなものを作ってしまうと、想定した値が取れませんでした。
(MySQLへの接続は「MySql.Data.MySqlClient」を使っています)
[ C#でMySQL接続してAUTO INCREMENT値を取得(ダメな例) ]
string conString= "Database=test;Data Source=localhost;User Id=test;Password=test"; public void Index() { using (MySqlConnection con = new MySqlConnection(conString)) { // DB接続→INSERT con.Open(); MySqlCommand cmd = con.CreateCommand(); MySqlTransaction tran; tran = con.BeginTransaction(); cmd.Connection = con; cmd.Transaction = tran; try { cmd.CommandText = "INSERT INTO test (name) VALUES ('1111')"; cmd.ExecuteNonQuery(); tran.Commit(); ShowAutoIncrementId(); // AutoIncrementの値を表示 } catch (Exception) { tran.Rollback(); } } } public void ShowAutoIncrementId() { using (MySqlConnection con = new MySqlConnection(conString)) { // DB接続→AutoIncrementIdを取得して表示する con.Open(); MySqlCommand cmd = con.CreateCommand(); cmd.Connection = con; cmd.CommandText = "SELECT LAST_INSERT_ID()"; object id = cmd.ExecuteScalar(); System.Diagnostics.Debug.WriteLine("***** ID : " + id); return; } }
【1回目の実行】
INSERTとSELECTが別セッション(428と429)になってしまったので取得できませんでした。
■結果
***** ID : 0
■MySQLログ
2019-03-06T07:39:31.579862Z 428 Query INSERT INTO test (name) VALUES ('111')
2019-03-06T07:39:31.582475Z 428 Query COMMIT
2019-03-06T07:39:31.660854Z 429 Connect test@localhost on test using SSL/TLS
2019-03-06T07:39:31.668533Z 429 Init DB test
2019-03-06T07:39:31.668751Z 429 Query SELECT LAST_INSERT_ID()
【2回目の実行】
なぜか「1」が取れました!?
コネクションプールで、1回目のINSERTと2回目のSELECTのセッションIDが同じ(428)になると、前回INSERTのIDが取得できてしまうようです。
■結果
***** ID : 1
■MySQLログ
2019-03-06T07:39:40.390591Z 429 Query INSERT INTO test (name) VALUES ('111')
2019-03-06T07:39:40.393070Z 429 Query COMMIT
2019-03-06T07:39:40.469436Z 428 Init DB test
2019-03-06T07:39:40.469689Z 428 Query SELECT LAST_INSERT_ID()
AUTO INCREMENTの値は、主キーや外部キーなどで使用することがあるかと思いますので、
「LAST_INSERT_ID()」関数を使用される際はご注意ください。
MySQL
0 件のコメント:
コメントを投稿