MySQLで最後に更新された行のIDを取得するにはどうすればよいですか?


134

PHPを使用してMySQLで最後に更新された行のIDを取得するにはどうすればよいですか?


2
mysqli_insert_id($ link)は、最後に更新された行のIDを正確に返します。私のプロジェクトでも同じ目的でこの関数を使用しています。同期クエリと非同期クエリの両方で使用できます。$ lastupdated_row_id = mysqli_insert_id($ link)をコードに挿入するだけで動作します。
Naeem Ul Wahhab、2013

1
更新した場合、行のIDはすでにわかりませんか?そうでない場合もあるのではないでしょうか。
JCharette 2014年

1
おそらく更新クエリでwhere句を使用していますが、selectクエリで同じwhere句を使用できないのはなぜですか?UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1
Salman A

回答:


236

私はこの問題の答えを見つけました:)

SET @update_id := 0;
UPDATE some_table SET column_name = 'value', id = (SELECT @update_id := id)
WHERE some_other_column = 'blah' LIMIT 1; 
SELECT @update_id;

EDIT aefxxによって

この手法をさらに拡張して、更新ステートメントの影響を受けるすべての行のIDを取得できます。

SET @uids := null;
UPDATE footable
   SET foo = 'bar'
 WHERE fooid > 5
   AND ( SELECT @uids := CONCAT_WS(',', fooid, @uids) );
SELECT @uids;

これは、すべてのIDがコンマで連結された文字列を返します。


6
これには0の賛成票があり、OPが要求していないmysql_insert_id()コメントは13であるとは信じられません。ありがとうPomyk、巧妙なトリック!
JakaJančar11年

1
あなたが持っているので、WHERE句を、あなたは、単に同じ使用することができますWHEREあなたの次のクエリでWHERE句をSELECT id FROM footable WHERE fooid > 5
サルマンA

4
多分誰もがこれを理解していますが、mysql_query();を使用する場合 これを3つの異なる呼び出しに分割する必要がありますが、機能します。
rael_kid

8
変数を使用する必要すらありません。LAST_INSERT_ID()次のの呼び出しで返される値を設定する引数を受け入れることができLAST_INSERT_ID()ます。例:UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';。これでSELECT LAST_INSERT_ID();、更新されたIDが返されます。詳細については、newtoverの回答を参照してください。
Joel

3
@SteveChilds私はニュートナーの質問にコメントしているだけで、あなたが説明している落とし穴に解決策を追加したいと思っています。UPDATE:がない場合は、LAST_INSERT_IDを0に設定しますUPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);。ただし、複数のIDを取得しないため、この答えの方が優れています。
martinczerwi 2015

33

ええと、私は答えの中で最も簡単な解決策を見つけられないことに驚いています。

仮定し、item_id整数のID列でitemsテーブルと次の文を使用して行を更新します。

UPDATE items
SET qwe = 'qwe'
WHERE asd = 'asd';

次に、ステートメントの直後に影響を受ける最新の行を知るには、ステートメントを次のように少し更新する必要があります。

UPDATE items
SET qwe = 'qwe',
    item_id=LAST_INSERT_ID(item_id)
WHERE asd = 'asd';
SELECT LAST_INSERT_ID();

実際に変更された行のみを更新する必要がある場合、データが行で変更されるかどうかをLAST_INSERT_IDチェックを介してitem_idの条件付き更新を追加する必要があります。


3
複数のクライアントがUPDATEステートメントを発行し、SELECTステートメント(またはmysql_insert_id())を使用して独自のシーケンス値を取得できるため、マルチユーザーに対して安全です。独自のシーケンス値を生成する他のクライアントに影響を与えたり、影響を受けたりすることはありません。あたりとしてdev.mysql.com/doc/refman/5.0/en/...
brutuscat

1
これは、item_idを最後に挿入されたレコードに設定しませんか?
arleslie 2014

2
@arleslie、上のbrutuscatのコメントにあるドキュメントへのリンクをたどると、表示されないことがわかります。これは、まさにそのケースの意図された動作です。
newtover 2014

1
これが正解です。クエリは少し直感に反するように見えますが、これはまさにMySQLのドキュメントに書かれているとおりです。
ティモシーゾーン2014

3
LAST_INSERT_ID(exprが)UPDATE呼び出しのexprの値を返しますので、場合、クエリは、あなたを混乱されます。また、このようにそれを使用することができます:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi

14

これは公式にはシンプルですが、直感に反します。あなたがやっている場合:

update users set status = 'processing' where status = 'pending'
limit 1

これを次のように変更します。

update users set status = 'processing' where status = 'pending'
and last_insert_id(user_id) 
limit 1

句のの追加はlast_insert_id(user_id)whereMySQLにその内部変数を見つかった行のID に設定するように指示しています。last_insert_id(expr)このように値を渡すと、最終的にその値が返されます。このようなIDの場合、これは常に正の整数であるため、常にtrueと評価され、where句に干渉しません。これは実際に一部の行が見つかった場合にのみ機能するため、影響を受ける行を必ず確認してください。その後、複数の方法でIDを取得できます。

MySQL last_insert_id()

LAST_INSERT_ID()を呼び出さなくてもシーケンスを生成できますが、このように関数を使用することの有用性は、ID値が最後に自動生成された値としてサーバーに保持されることです。複数のクライアントがUPDATEステートメントを発行してSELECTステートメント(またはmysql_insert_id())で独自のシーケンス値を取得できるため、独自のシーケンス値を生成する他のクライアントに影響を与えたり、影響を受けたりすることがないため、マルチユーザーセーフです。

MySQL mysql_insert_id()

以前のINSERTまたはUPDATEステートメントによってAUTO_INCREMENT列に生成された値を返します。AUTO_INCREMENTフィールドを含むテーブルに対してINSERTステートメントを実行した後、またはINSERTまたはUPDATEを使用してLAST_INSERT_ID(expr)で列の値を設定した後に、この関数を使用します。

LAST_INSERT_ID()とmysql_insert_id()の違いの理由は、mysql_insert_id()がAUTO_INCREMENTカラムで何が起こっているかについてより正確な情報を提供しようとする一方で、LAST_INSERT_ID()がスクリプトで簡単に使用できるためです。

PHP mysqli_insert_id()

LAST_INSERT_ID()関数を使用してINSERTまたはUPDATEステートメントを実行すると、mysqli_insert_id()関数によって返される値も変更されます。

すべてを一緒に入れて:

$affected_rows = DB::getAffectedRows("
    update users set status = 'processing' 
    where status = 'pending' and last_insert_id(user_id) 
    limit 1"
);
if ($affected_rows) {
    $user_id = DB::getInsertId();
}

(参考:DBクラスはこちらです。)


注意してください:これはマルチ接続セーフであり、last_insert_idまたはmysql_insert_id(およびmysqli_insert_id、私はチェックしなかったかもしれません)の永続化された値は接続ごとです。驚くばかり!
ライアンS

10

これはSalman Aの回答と同じ方法ですが、実際に必要なコードは次のとおりです。

まず、テーブルを編集して、行が変更されるたびに自動的に追跡されるようにします。行が最初にいつ挿入されたかだけを知りたい場合は、最後の行を削除してください。

ALTER TABLE mytable
ADD lastmodified TIMESTAMP 
    DEFAULT CURRENT_TIMESTAMP 
    ON UPDATE CURRENT_TIMESTAMP;

次に、最後に更新された行を見つけるために、このコードを使用できます。

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

このコードはすべて、MySQLとPostgreSQL:テーブルへの「最終変更時刻」列の追加MySQLマニュアル:行のソートから引き上げられています。組み立てたところです。


7
最初の挿入クエリの直後に2番目の挿入が行われた場合、このメソッドは誤ったIDをフェッチする可能性があります。ただし、このクエリで「WHERE」を使用する場合、つまりSELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1 WHERE(最後の挿入クエリに関連するいくつかの条件)の場合、誤ったIDのフェッチを防ぐことができます。
Naeem Ul Wahhab 2013年

1
@ TheNoble-Coderこれは本当です。特定の更新クエリに影響を与えた行のIDを取得する必要がある場合は、Pomykの手法を使用します。ここでのこの手法は、非同期で使用する場合に非常に役立ちます。非同期で使用する場合、最後の絶対更新のみが必要です。
Chad von Nau 2013

5

クエリ:

$sqlQuery = "UPDATE 
            update_table 
        SET 
            set_name = 'value' 
        WHERE 
            where_name = 'name'
        LIMIT 1;";

PHP関数:

function updateAndGetId($sqlQuery)
{
    mysql_query(str_replace("SET", "SET id = LAST_INSERT_ID(id),", $sqlQuery));
    return mysql_insert_id();
}

それは私にとっては仕事です;)


私は同じように実行しましたが、動作が異なります

3

上記の受け入れられた回答の
詳細について:=&について疑問に思っていた人のために=

との大きな違いは:==それは:=どこでも変数代入演算子として機能するのに対し=、SETステートメントではそのようにしか機能せず、それ以外では比較演算子であることです。

したがって、変更SELECT @var = 1 + 1;@varずにブール値(@varの現在の値に応じて1または0)を返し2SELECT @var := 1 + 1;変更@varして2返します。 [ソース]


ねえ、ありがとう。それらが意味することは、実際には上記の受け入れられた答えよりも興味深いです。
グリーン

2

ちょっと、私はそのようなトリックが必要だった-私は別の方法でそれを解決しました、多分それはあなたのために働くでしょう。これはスケーラブルなソリューションではなく、大きなデータセットの場合は非常に悪いことに注意してください。

クエリを2つの部分に分割します-

まず、更新する行のIDを選択し、一時テーブルに保存します。

次に、更新ステートメントの条件をに変更して、元の更新を実行しwhere id in temp_tableます。

そして、同時性を確保するために、あなたがする必要がロックし、この二つのステップの前にテーブルをして、最後にロックを解除します。

繰り返しますが、これはで終わるクエリで機能します。そのlimit 1ため、一時テーブルも使用せず、最初のの結果を格納するための変数を使用しますselect

私は常に1行のみを更新することがわかっているため、この方法を使用します。コードは単純です。


2
SET @uids := "";
UPDATE myf___ingtable
   SET id = id
   WHERE id < 5
  AND ( SELECT @uids := CONCAT_WS(',', CAST(id AS CHAR CHARACTER SET utf8), @uids) );
SELECT @uids;

私はidをキャストしなければなりませんでした(どうしてだめなのか)...または@uidsコンテンツを取得できません(これはblobでした)ところで、Pomykの回答に感謝します!


2

最後に更新された行のIDは、その行を見つけて更新するために「updateQuery」で使用するIDと同じです。そのため、とにかくそのIDを保存(呼び出し)するだけです。

last_insert_id()に依存しますAUTO_INCREMENTが、最終更新IDはそうではありません。


3
更新がIDからではなく、別の属性セットから行われた場合はどうなりますか?
セバス2014年

2

私の解決策は、最初にselectコマンドで "id"(@uids)を決定し、このIDを@uidsで更新した後です。

SET @uids := (SELECT id FROM table WHERE some = 0 LIMIT 1);
UPDATE table SET col = 1 WHERE id = @uids;SELECT @uids;

それは私のプロジェクトで働いた。


1

挿入のみを行い、同じセッションから挿入したい場合は、Peirixの回答に従ってください。変更を行う場合は、データベーススキーマを変更して、最後に更新されたエントリを格納する必要があります。

別のセッションからのものである可能性がある最後の変更のIDが必要な場合(つまり、現在実行中のPHPコードによって実行されたIDではなく、別の要求に応答して実行されたID)、次を追加できます。 last_modifiedと呼ばれるテーブルへのTIMESTAMP列(http://dev.mysql.com/doc/refman/5.1/en/datetime.htmlを参照してください)。次に、更新するときに、last_modified = CURRENT_TIMEを設定します。

これを設定したら、次のようなクエリを使用できます。SELECT id FROM table ORDER BY last_modified DESC LIMIT 1; 最後に変更された行を取得します。


-9

それほど長いMysqlコードは必要ありません。PHPでは、クエリは次のようになります。

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.