2016-04-14 6 views
0

私はテーブルの最後の更新された行のIDを選択しようとしていますが、この質問はHow to get ID of the last updated row in MySQL?です。トリックは、「MySQLで最後に更新された行のIDをどのように取得するのですか?

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

解決策は機能しますが、空の文字列ではなくヌルに設定する理由はわかりません。このステートメントは、リミット句が追加されていても、一致する行ではなく影響を受ける行のみを選択する理由は何ですか。これはMySQLで定義された動作ですか? MySQLマニュアルのどのページを見上げますか?あなたは空の文字列に@uidsを初期化する場合は、それらの間のカンマでfooid''を連結するので、

mysql> select * from transaction_test; 
+----+--------+------------+ 
| id | value1 | value2  | 
+----+--------+------------+ 
| 1 |  1 | 1460600984 | 
| 2 |  2 | 1460598960 | 
+----+--------+------------+ 
2 rows in set (0.00 sec) 

mysql> set @ids=null;update transaction_test set value2=unix_timestamp(now()) where 1=1 and (SELECT @ids:=concat_ws(',',@ids,value1) ) limit 1;select @ids; 
Query OK, 0 rows affected (0.00 sec) 

Query OK, 1 row affected (0.05 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

+------+ 
| @ids | 
+------+ 
| 1 | 
+------+ 
1 row in set (0.00 sec) 

mysql> set @ids='';update transaction_test set value2=unix_timestamp(now()) where 1=1 and (SELECT @ids:=concat_ws(',',@ids,value1) ) limit 1;select @ids; 
Query OK, 0 rows affected (0.00 sec) 

Query OK, 0 rows affected (0.00 sec) 
Rows matched: 0 Changed: 0 Warnings: 0 

+------+ 
| @ids | 
+------+ 
| ,1,2 | 
+------+ 
1 row in set (0.00 sec) 
+0

あなたは 'UPDATE'に' LIMIT'を適用していますか? –

+0

@MichaelBerkowskiはい、試合の一部を更新して選択する必要があります。 – rox

+0

[user-variables](http://dev.mysql.com/doc/refman/5.7/en/user-variables.html)*** SELECTステートメントでは、各選択式は、クライアント。 *** – rox

答えて

2

、そしてCONCAT_WS(',', fooid, @uids)は、fooid,の代わりに、それは最初の連結を行うだけでfooidになります。しかし、CONCAT_WS()の引数のいずれかがNULLの場合、それは完全に無視され、隣接する要素との間にはカンマは入れません。

ANDの短絡を行うので、影響を受ける行のみを選択します。つまり、パラメータは左から右に評価され、最初のパラメータがFALSEであれば、2番目のパラメータはまったく評価されません。したがって、fooid > 5TRUEの場合にのみ@uids := ...割り当てが実行されます。

LIMIT句がある場合、その動作は、注文している列がインデックスされているかどうかによって異なります。存在する場合は、インデックスを順番にスキャンしてからWHERE句を評価し、制限数に達した時点で停止するので、制限内の行のみが@uidsに含まれます。または、ORDER BY句がない場合は、制限に達するまでテーブルをスキャンするだけです。

ただし、信頼性の高いこの依存関係は、クエリオプティマイザがクエリを分析する方法によって異なります。

ただし、順序付け列が索引付けされていない場合、または問合せオプティマイザが上記の最適化を実行できない場合は、WHERE句に一致するすべての行を一時表に選択し、それを注文してください。その場合、@uidsには、制限内のものだけでなく、すべての一致するIDが含まれます。これを解決するには、サブクエリを使用します。

SET @uids := null; 
UPDATE footable AS t1 
JOIN (SELECT fooid 
     FROM footable 
     WHERE fooid > 5 
     ORDER BY somecolumn 
     LIMIT 10) AS t2 
ON t1.fooid = t2.fooid 
SET t1.foo = 'bar' 
WHERE @uids := CONCAT_WS(',', fooid, @uids); 
SELECT @uids; 
+0

紛らわしい結果は、空文字列の場合でも影響を受けていない行が選択されるということです。 – rox

+0

私は質問に自分のテストを追加しました。これはあなたが確認できるでしょう – rox

+0

それは間違いなく間違っています、それはクエリプランナーに影響するようです。確かな結果を得るには、 'JOIN'メソッドを使います。 – Barmar

関連する問題