Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Post “2021-09-05--mysql-update-with-sub-query/index” #9

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions content/posts/2021-09-05--mysql-update-with-sub-query/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ cover: Screen_Shot_2021-09-05.png
author: hideyoshi
---
# 【MySQL】サブクエリを使ったUPDATEを実行する

こんにちは。 [GAOGAO](https://gaogao.asia/) にてスタートアップスタジオのエンジニアをしております [@mass-min](https://twitter.com/masumi_sugae) と申します。
GAOGAO では秀吉と呼ばれています。どうぞよろしくお願いいたします。

![【MySQL】サブクエリを使ったUPDATEを実行する](Screen_Shot_2021-09-05.png "【MySQL】サブクエリを使ったUPDATEを実行する")

## 結論

サブクエリで扱うテーブルは、 UPDATE 対象のテーブルとは別物扱いにする必要があります。

更新対象テーブルと同一のテーブルに対してサブクエリを書きたい場合は、サブクエリでの取得結果に対してエイリアスを貼るようにしましょう。

前提
---
## 前提

下記のようなテーブル構成になっているものとします。

![ER_image](er.png)
Expand Down Expand Up @@ -46,8 +50,8 @@ mysql> SELECT * FROM posts;
3 rows in set (0.00 sec)
```

サブクエリを用いた UPDATE の失敗
---
## サブクエリを用いた UPDATE の失敗

`users` テーブルは `status` の default 値が `registered` で、1つでも記事を公開する(`published_at` が null でない `posts` を1つ以上持つ)と以降 `status` は `posted` になる運用をしています。

この UPDATE 処理を日次バッヂ処理で回すことを考えます。
Expand Down Expand Up @@ -108,8 +112,8 @@ mysql> UPDATE users
ERROR 1093 (HY000): You can't specify target table 'users' for update in FROM clause
```

エラー原因・解決方法
---
## エラー原因・解決方法

結論から言うと、以下のようにサブクエリ部分を書き換えることで解決できます。

```sql
Expand All @@ -131,7 +135,7 @@ WHERE

MySQL では、同一テーブルの条件をサブクエリに入れることは出来ません。ドキュメントでも以下のように記述があります。

>You cannot update a table and select directly from the same table in a subquery. You can work around this by using a multi-table update in which one of the tables is derived from the table that you actually wish to update, and referring to the derived table using an alias.
> You cannot update a table and select directly from the same table in a subquery. You can work around this by using a multi-table update in which one of the tables is derived from the table that you actually wish to update, and referring to the derived table using an alias.

https://dev.mysql.com/doc/refman/5.6/en/update.html

Expand All @@ -144,6 +148,7 @@ https://dev.mysql.com/doc/refman/5.6/en/update.html
各ステップの取得結果を確認してみましょう。

### id 取得用 SQL

以下では取得対象のレコードの組み合わせを INNER JOIN でそのまま全て取得していますが、このステップの時点で DISTINCT の宣言をしても良いです。

```sql
Expand Down Expand Up @@ -171,7 +176,7 @@ mysql> SELECT DISTINCT id FROM (SELECT users.id FROM users INNER JOIN posts ON u

### さらにサブクエリ化して UPDATE 文を実行

```
```sql
mysql> UPDATE users SET status = 'posted' WHERE id IN (SELECT DISTINCT id FROM (SELECT users.id FROM users INNER JOIN posts ON users.id = posts.user_id WHERE posts.published_at IS NOT NULL) AS tmp_table);
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
Expand All @@ -190,11 +195,11 @@ mysql> SELECT * FROM users;
これでアップデートができるようになりました。

## まとめ

サブクエリで扱うテーブルは、 UPDATE 対象のテーブルとは別物扱いにする必要があります。

更新対象テーブルと同一のテーブルに対してサブクエリを書きたい場合は、サブクエリでの取得結果に対してエイリアスを貼るようにしましょう。


## 最後に

弊社 GAOGAO は現在副業含めて40名以上のエンジニアの方が参画し、グローバル(シンガポール、バンコク、US、日本など)で20社以上お客様の開発のお手伝いをさせていただいております。
Expand All @@ -204,6 +209,6 @@ mysql> SELECT * FROM users;

世界中で「モノつくり」の連鎖を起こすことができる世界を実現するための仕組みを是非一緒に作っていきましょう!

参考URL
---
https://qiita.com/Kohei-Sato-1221/items/d1cbdc1d3affcd9c3a9e
## 参考URL

https://qiita.com/Kohei-Sato-1221/items/d1cbdc1d3affcd9c3a9e