質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

3回答

12875閲覧

[MySQL]Updateしたデータをselectしたい

pac894398

総合スコア429

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2016/11/25 11:34

題名の通りです。

update の際の where句の条件では 複数が該当するのですが、
limit 1 で 1件しか更新していません。

更新されたデータを取得したいのです。

###自分なりにしてみたこと
最終更新日時を記録したカラムを作って それが最も古いデータを select した。
→ 同じ時刻に update した人がいたらおかしくなる。

insert の last_insert_id(); にあたる方法みたいなのはないのでしょうか?
それとも update と select を1文にして 同時にする方法など...

お回答お待ちしております。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

既に「解決済み」となっていますが、、

ご想像の通り、SELECT ... FOR UPDATE 構文を使うことで、望む動作を実現できます。
(ただし、操作対象のテーブルのエンジンが InnoDB の場合に限ります)
https://dev.mysql.com/doc/refman/5.6/ja/innodb-locking-reads.html

具体的には、以下のように使用します。

sql

1mysql> CREATE TABLE test ( 2 -> id INT PRIMARY KEY AUTO_INCREMENT, 3 -> value INT 4 -> ); 5Query OK, 0 rows affected (0.07 sec) 6 7mysql> INSERT INTO test (value) VALUES (1), (2), (2), (4), (7); 8Query OK, 5 rows affected (0.00 sec) 9Records: 5 Duplicates: 0 Warnings: 0 10 11mysql> SELECT * FROM test; 12+----+-------+ 13| id | value | 14+----+-------+ 15| 1 | 1 | 16| 2 | 2 | 17| 3 | 2 | 18| 4 | 4 | 19| 5 | 7 | 20+----+-------+ 215 rows in set (0.00 sec) 22 23mysql> BEGIN; 24Query OK, 0 rows affected (0.00 sec) 25 26mysql> SELECT id FROM test WHERE value = 2 LIMIT 1 FOR UPDATE; 27+----+ 28| id | 29+----+ 30| 2 | 31+----+ 321 row in set (0.00 sec) 33 34 35#1 36# ここで、別のターミナルなどから testテーブルの id = 2 を含むレコードに対して 37# UPDATE/DELETE または SELECT ... FOR UPDATE 文を実行 38 39 40mysql> UPDATE test SET value = 10 WHERE id = 2; 41Query OK, 1 row affected (0.01 sec) 42Rows matched: 1 Changed: 1 Warnings: 0 43 44mysql> COMMIT; 45Query OK, 0 rows affected (0.00 sec) 46 47mysql> SELECT * FROM test; 48+----+-------+ 49| id | value | 50+----+-------+ 51| 1 | 1 | 52| 2 | 10 | 53| 3 | 2 | 54| 4 | 4 | 55| 5 | 7 | 56+----+-------+ 575 rows in set (0.00 sec)

上述の#1部分で、別のターミナルなどから同じ MySQL にログインし、testテーブルの id = 2 を含むレコードに対して UPDATE/DELETE または SELECT ... FOR UPDATE 文を実行してみてください。
COMMITするまで、SQL文の実行がブロックされる(応答が返ってこない)ことが確認できると思います。

投稿2016/11/28 02:57

KiyoshiMotoki

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

主キー が割り当てられているので まずは updateしたい条件で select し、
主キーで該当データを削除、
変更を加えたデータを insert しました。

しかし この方法では 同時にアクセスがあった場合に 不具合が起きます。

select for update を使用して 先に情報取得→更新 とすればいけるかも...?

投稿2016/11/25 12:46

pac894398

総合スコア429

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

複数条件をlimitで処理しているならorder byしているはずですから
おなじorder byをかけてlimit 1でデータをとればよいのでは?

sample

timestampで管理

SQL

1create table tbl(id int not null primary key,val int ,ts timestamp); 2insert into tbl(id,val) values(1,100),(2,150),(3,300); 3update tbl set val=400 where id=2; 4select * from tbl order by ts desc limit 1;

投稿2016/11/25 11:59

編集2016/11/28 03:16
yambejp

総合スコア117740

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pac894398

2016/11/25 12:41

データが他から書き換えられたりしたら 困るんですね...。
pac894398

2016/11/25 12:42

[追記] where 句で 検索条件にしているパラメータも update しております。
yambejp

2016/11/28 03:09

まぁ普通最新データをとりたいならtimestampカラムを作っておくような気がしますけどね
KiyoshiMotoki

2016/11/28 03:23

その"sample"だと、全てのカラム ts の値は NULL にしかなりませんよ。 mysql> create table tbl(id int not null primary key,val int ,ts timestamp); Query OK, 0 rows affected (0.06 sec) mysql> insert into tbl(id,val) values(1,100),(2,150),(3,300); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from tbl; +----+------+------+ | id | val | ts | +----+------+------+ | 1 | 100 | NULL | | 2 | 400 | NULL | | 3 | 300 | NULL | +----+------+------+ 3 rows in set (0.00 sec)
KiyoshiMotoki

2016/11/28 03:33 編集

失礼しました。 私の環境では、システム変数 explicit_defaults_for_timestamp が ON になっていました。 (デフォルトは OFF) この変数の値が OFF だと、自動的に現在時刻が格納されるのですね。 https://dev.mysql.com/doc/refman/5.6/ja/server-system-variables.html#sysvar_explicit_defaults_for_timestamp mysql> set @@local.explicit_defaults_for_timestamp = 0; Query OK, 0 rows affected (0.06 sec) mysql> create table tbl(id int not null primary key,val int ,ts timestamp); Query OK, 0 rows affected (0.01 sec) mysql> insert into tbl(id,val) values(1,100),(2,150),(3,300); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> update tbl set val=400 where id=2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from tbl; +----+------+---------------------+ | id | val | ts | +----+------+---------------------+ | 1 | 100 | 2016-11-28 12:29:41 | | 2 | 400 | 2016-11-28 12:29:45 | | 3 | 300 | 2016-11-28 12:29:41 | +----+------+---------------------+ 3 rows in set (0.00 sec)
yambejp

2016/11/28 03:38

KiyoshiMotokiさん、フォローありがとうございます explicit_defaults_for_timestampの設定があるのですね 今後はユーザー環境を考慮して、timestampについて記載をするときには 設定についても補足するようにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問