MySQL エラー 1093: FROM 句で更新対象テーブルを指定できない - 原因と解決方法
エラー 1093: FROM 句で更新対象テーブルを指定できない - 詳細解説
MySQL で UPDATE
クエリを実行時に、FROM
句で指定したテーブルを更新しようとすると、エラー 1093 "Can't specify target table for update in FROM clause" が発生します。これは、サブクエリを使用するなど、いくつかの状況で起こり得ます。
原因
このエラーは、以下のいずれかの理由で発生します。
- サブクエリで更新対象テーブルを参照: サブクエリで更新対象テーブルを参照する場合、MySQL は更新対象テーブルをロックできません。
- JOIN と UPDATE の組み合わせ:
JOIN
とUPDATE
を組み合わせる場合、FROM
句で指定されたすべてのテーブルが更新対象となります。 - 一時テーブルの使用: 一時テーブルを更新しようとすると、エラーが発生します。
解決方法
このエラーを解決するには、以下の方法があります。
サブクエリを使用せずに、UPDATE
クエリを直接実行します。
例:
# サブクエリを使用する
UPDATE users
SET email = (SELECT email FROM other_table WHERE id = 1)
WHERE id = 2;
# サブクエリを使用しない
UPDATE users
SET email = '[email protected]'
WHERE id = 2;
JOIN
と UPDATE
を組み合わせる場合は、UPDATE
句で更新対象テーブルを明示的に指定します。
# 間違った例
UPDATE users
JOIN other_table ON users.id = other_table.user_id
SET users.email = '[email protected]'
WHERE other_table.id = 1;
# 正しい例
UPDATE users
SET email = '[email protected]'
WHERE users.id IN (SELECT user_id FROM other_table WHERE id = 1);
# 一時テーブルを使用する
CREATE TEMPORARY TABLE tmp_users AS
SELECT * FROM users;
UPDATE tmp_users
SET email = '[email protected]'
WHERE id = 2;
# 一時テーブルを使用しない
UPDATE users
SET email = '[email protected]'
WHERE id = 2;
その他の解決方法
上記の方法で解決できない場合は、以下の方法も検討できます。
ALIAS
を使用して、サブクエリで更新対象テーブルに別名を付ける。UPDATE
クエリを複数に分けて実行する。- ストアドプロシージャを使用する。
補足
- このエラーは、MySQL だけでなく、他のデータベースでも発生する可能性があります。
- エラーメッセージの詳細を確認することで、エラーの原因を特定しやすくなります。
この情報は参考情報として提供されており、特定の状況に対する専門的なアドバイスとして解釈されるべきではありません。
サブクエリを使用しない
# users テーブルの email カラムを更新
UPDATE users
SET email = '[email protected]'
WHERE id = 2;
JOIN と UPDATE を適切に組み合わせる
# users テーブルの email カラムを、other_table の id カラムに基づいて更新
UPDATE users
SET email = other_table.email
FROM users
JOIN other_table ON users.id = other_table.user_id
WHERE other_table.id = 1;
一時テーブルを使用しない
# users テーブルの email カラムを更新
UPDATE users
SET email = '[email protected]'
WHERE id = 2;
# users テーブルの email カラムを更新
UPDATE users u
SET email = (SELECT email FROM other_table WHERE id = 1)
WHERE u.id = 2;
# users テーブルの email カラムを更新
# 1. users テーブルの id 2 のレコードを取得
SELECT * FROM users WHERE id = 2;
# 2. 取得したレコードの email カラムを更新
UPDATE users
SET email = '[email protected]'
WHERE id = 2;
# ストアドプロシージャを作成
DELIMITER //
CREATE PROCEDURE update_user_email(
IN user_id INT,
IN new_email VARCHAR(255)
)
BEGIN
UPDATE users
SET email = new_email
WHERE id = user_id;
END //
DELIMITER ;
# ストアドプロシージャを実行
CALL update_user_email(2, '[email protected]');
- このサンプルコードは、あくまでも参考情報として提供されています。
- 実際のコードは、ご自身の環境に合わせて変更する必要があります。
エラー 1093: FROM 句で更新対象テーブルを指定できない - その他の方法
WITH
句を使用すると、サブクエリを CTE (Common Table Expression) として定義し、その CTE を UPDATE
クエリで参照できます。
WITH t AS (
SELECT * FROM users
)
UPDATE t
SET email = '[email protected]'
WHERE id = 2;
LATERAL JOIN
は、サブクエリを FROM 句ではなく JOIN 句で使用できる機能です。
UPDATE users
SET email = t.email
FROM users
LATERAL JOIN (
SELECT email FROM other_table WHERE id = 1
) t;
CASE
式を使用すると、条件に応じて異なる値を更新できます。
UPDATE users
SET email = CASE WHEN id = 1 THEN '[email protected]'
WHEN id = 2 THEN '[email protected]'
ELSE email
END
WHERE id IN (1, 2);
UPDATE
トリガーを使用すると、UPDATE
クエリが実行される前に、自動的に別のテーブルを更新できます。
CREATE TRIGGER update_user_email
BEFORE UPDATE ON users
FOR EACH ROW
BEGIN
UPDATE other_table
SET email = NEW.email
WHERE user_id = OLD.id;
END;
- 上記の方法は、状況によっては有効な解決策となる可能性があります。
mysql subquery sql-delete