- MySQL
MySQL ERROR 1093の直し方|同じテーブルの更新
ERROR 1093 (HY000): You can't specify target table 'customer' for update in FROM clause は、UPDATE・DELETE するテーブルを、同じ文のサブクエリの中で直接読んだときに MySQL が出すエラーです。 「更新しながら、同じテーブルを読む」書き方を、MySQL は許していません(MySQL 公式マニュアル)。
直し方は3つです。どれも、確認環境で同じ結果になりました。
| 直し方 | 書き方のポイント |
|---|---|
| JOIN に書き換える | DELETE c1 FROM customer c1 JOIN customer c2 ON ... |
| 派生テーブル(サブクエリの中のサブクエリ)で包む | WHERE id NOT IN (SELECT id FROM (SELECT ... FROM customer) AS t) |
| WITH 句(CTE)で先に計算する | WITH keep AS (SELECT ... FROM customer) DELETE ...(MySQL 8.0) |
確認環境:MySQL 8.0.46、PostgreSQL 16.15(確認日 2026年10月11日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「MySQL ERROR 1093の直し方|同じテーブルの更新」
再現:重複行を1件残して消す
同じメールアドレスの顧客が重複しています。メールアドレスごとに、id が最も小さい行だけを残したいとします。
id email name
1 a@x 佐藤
2 b@x 鈴木
3 a@x 佐藤(重複)
4 c@x 高橋
5 b@x 鈴木(重複)
6 a@x 佐藤(重複2)
DELETE FROM customer
WHERE id NOT IN (SELECT MIN(id) FROM customer GROUP BY email);
ERROR 1093 (HY000): You can't specify target table 'customer' for update in FROM clause
削除する customer を、サブクエリの FROM customer で読んでいるためです。UPDATE でも同じです。
UPDATE customer SET score = score + 10
WHERE score < (SELECT AVG(score) FROM customer); -- 平均より低い人に10点足す
-- ERROR 1093 (HY000): You can't specify target table 'customer' for update in FROM clause
直し方1:JOIN に書き換える
DELETE c1
FROM customer c1
JOIN customer c2 ON c1.email = c2.email AND c1.id > c2.id;
id email name
1 a@x 佐藤
2 b@x 鈴木
4 c@x 高橋 ← 各メールアドレスの最小の id だけが残った
「自分より id が小さい同じメールアドレスの行がある行」を消す、という考え方です。UPDATE は、集計した結果と JOIN します。
UPDATE customer c
JOIN (SELECT AVG(score) AS a FROM customer) t ON c.score < t.a
SET c.score = c.score + 10;
id score
1 60 ← 50 → 60(平均 63.3 より低い)
2 80
3 70 ← 60 → 70
4 40 ← 30 → 40
5 90
6 70 ← 変わらず(平均以上)
直し方2:派生テーブルで包む
サブクエリを、もう一段 SELECT ... FROM ( ... ) AS 別名 で包みます。
DELETE FROM customer
WHERE id NOT IN (
SELECT id FROM (SELECT MIN(id) AS id FROM customer GROUP BY email) AS keep
);
UPDATE customer SET score = score + 10
WHERE score < (SELECT avg_score FROM (SELECT AVG(score) AS avg_score FROM customer) AS t);
確認環境では、どちらも JOIN と同じ結果になりました。内側のサブクエリの結果が、いったん一時的な表として作られるため、「更新しながら同じテーブルを読む」状態にならず、エラーを避けられます。AS keep のような別名は必須です(派生テーブルには名前が要る)。
「派生テーブルでも効かない」と言われるケース
MySQL 公式マニュアルでは、派生テーブルが外側のクエリに統合(merge)されると、この回避が効かない場合があるとされ、NO_MERGE ヒントや optimizer_switch の derived_merge=off で、一時的な表を作らせる方法が案内されています。
UPDATE /*+ NO_MERGE(d) */ customer,
(SELECT id FROM customer WHERE score < 60) AS d
SET customer.score = 0
WHERE customer.id = d.id;
確認環境(MySQL 8.0.46)では、ヒントを付けなくても、次の書き方はすべてエラーにならずに通りました。
| 書き方 | 結果(8.0.46) |
|---|---|
DELETE ... WHERE id IN (SELECT id FROM (SELECT id FROM customer WHERE ...) AS t) |
通った |
UPDATE customer, (SELECT id FROM customer WHERE ...) AS d SET ... WHERE customer.id = d.id |
通った |
上に /*+ NO_MERGE(d) */ を付けたもの |
通った |
版や書き方によって結果が変わる可能性があるため、派生テーブルで包んでも 1093 が出るときは NO_MERGE を付けると覚えておきます。
直し方3:WITH 句(MySQL 8.0)
WITH keep AS (SELECT MIN(id) AS id FROM customer GROUP BY email)
DELETE FROM customer WHERE id NOT IN (SELECT id FROM keep);
確認環境では、これも id 1・2・4 が残り、同じ結果になりました。何を残すかが先に名前付きで書かれるので、3つの中では読みやすい書き方です。
実行する前に、消える行を確かめる
DELETE を書き換えたら、同じ条件の SELECT で、消える行を先に確かめます。
SELECT c1.*
FROM customer c1
JOIN customer c2 ON c1.email = c2.email AND c1.id > c2.id; -- 消える行(3, 5, 6)
本番のデータなら、トランザクションの中で実行して、件数を確かめてから COMMIT します。
START TRANSACTION;
DELETE c1 FROM customer c1 JOIN customer c2 ON c1.email = c2.email AND c1.id > c2.id;
SELECT ROW_COUNT(); -- 消えた件数
-- 想定どおりなら COMMIT、違えば ROLLBACK
PostgreSQL では同じ SQL が通る
(PostgreSQL 16)
DELETE FROM customer2 WHERE id NOT IN (SELECT min(id) FROM customer2 GROUP BY email); ← 通る
UPDATE customer2 SET score = score + 10 WHERE score < (SELECT avg(score) FROM customer2); ← 通る
1093 は MySQL 特有の制限です。PostgreSQL や他の DB で書いた SQL を MySQL に移すときに出会います。
確認の手順(チェックリスト)
| 順番 | 確認すること | 方法 |
|---|---|---|
| 1 | 更新するテーブルを、サブクエリで読んでいないか | UPDATE t ... (SELECT ... FROM t)、DELETE FROM t ... (SELECT ... FROM t) |
| 2 | 書き換える | JOIN、派生テーブル(別名つき)、WITH 句 |
| 3 | まだ出るなら | /*+ NO_MERGE(別名) */ |
| 4 | 消える行・変わる行 | 同じ条件の SELECT で先に確かめる |
| 5 | 本番 | トランザクションの中で ROW_COUNT() を見てから COMMIT |
よくある質問
Q. SELECT だけなら同じテーブルをサブクエリで読めますか。 A. 読めます。1093 は、UPDATE・DELETE の対象のテーブルを、同じ文のサブクエリで読んだときだけ出ます。
Q. 重複を消すなら、ほかの方法はありますか。
A. 重複を残す行のルール(最小の id、最新の日時など)を決めてから、ウィンドウ関数(ROW_NUMBER())で番号を付けて消す方法もあります。重複の探し方と消し方の全体は、関連記事の「SQLで重複データを抽出・削除する方法」で詳しく比べています。
まとめ
- UPDATE・DELETE するテーブルを、同じ文のサブクエリで読むと 1093。MySQL 特有の制限
- 直し方は JOIN・派生テーブル(別名つき)・WITH 句の3つ
- 派生テーブルでも出るなら
NO_MERGEヒント - 消す前に同じ条件の SELECT で確かめ、本番はトランザクションの中で
- PostgreSQL では同じ SQL が通る。移行のときに出会いやすい
参考・出典
確認日はいずれも 2026年10月11日です。
- MySQL 8.0 Reference Manual「UPDATE Statement」:https://dev.mysql.com/doc/refman/8.0/en/update.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「MySQL ERROR 1093の直し方|同じテーブルの更新」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。