MySQL エラー 1093 - FROM 句で更新のターゲット テーブルを指定できません
-
09-06-2019 - |
質問
テーブルがあります story_category
私のデータベースには壊れたエントリがあります。次のクエリは破損したエントリを返します。
SELECT *
FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
私はそれらを実行して削除しようとしました:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category
INNER JOIN story_category ON category_id=category.id);
しかし、次のエラーが発生します。
#1093 - FROM 句で更新のターゲット テーブル 'story_category' を指定することはできません
どうすればこれを克服できますか?
解決
アップデート:この回答では、一般的なエラー分類について説明します。OP の正確なクエリを最適に処理する方法についてのより具体的な回答については、この質問に対する他の回答を参照してください。
MySQL では、SELECT 部分で使用するのと同じテーブルを変更することはできません。
この動作は次の場所に文書化されています。http://dev.mysql.com/doc/refman/5.6/en/update.html
おそらく、テーブルをそれ自体に結合することができます
ロジックが単純でクエリを再形成できる場合は、サブクエリを削除し、適切な選択基準を使用してテーブルをそれ自体に結合します。これにより、MySQL はテーブルを 2 つの異なるものとして認識し、破壊的な変更を続行できるようになります。
UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col
あるいは、サブクエリを from 句のさらに深くネストしてみてください。
サブクエリが絶対に必要な場合は、回避策がありますが、パフォーマンスを含むいくつかの理由で醜いです。
UPDATE tbl SET col = (
SELECT ... FROM (SELECT.... FROM) AS x);
FROM 句内のネストされたサブクエリは、 暗黙の一時テーブル, そのため、更新しているのと同じテーブルとしてカウントされません。
...ただしクエリオプティマイザーには注意してください
ただし、から注意してください MySQL 5.7.6 その後、オプティマイザがサブクエリを最適化しても、依然としてエラーが発生する可能性があります。幸いなことに、 optimizer_switch
変数を使用して、この動作をオフにすることができます。ただし、これを短期的な修正や 1 回限りの小さなタスクとして行うことはお勧めできません。
SET optimizer_switch = 'derived_merge=off';
おかげで ピーター V.ムルヒ このアドバイスについてはコメント欄で。
テクニック例はシュワルツ男爵からのもので、 最初はNabbleで公開されました, 、ここで言い換えて拡張します。
他のヒント
ネクサスレックス を提供した とても良い解決策 同じテーブルから結合して削除する場合。
これを行う場合:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id AS cid FROM category
INNER JOIN story_category ON category_id=category.id
)
エラーが発生します。
ただし、条件をもう 1 つの選択でラップすると、次のようになります。
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT cid FROM (
SELECT DISTINCT category.id AS cid FROM category
INNER JOIN story_category ON category_id=category.id
) AS c
)
それは正しいことをするでしょう!!
説明: クエリ オプティマイザーは次のことを行います。 派生マージ最適化 最初のクエリは (エラーで失敗します)、2 番目のクエリは条件を満たしません。 派生マージ最適化. 。したがって、オプティマイザは最初にサブクエリを実行することを強制されます。
の inner join
サブクエリ内の は不要です。のエントリを削除したいようです story_category
どこ category_id
には入っていない category
テーブル。
これを行う:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category);
その代わりに:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
最近、同じテーブル内のレコードを更新する必要があり、以下のように実行しました。
UPDATE skills AS s, (SELECT id FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development'
WHERE s.id = p.id;
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT cid FROM (
SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id
) AS c
)
できないなら
UPDATE table SET a=value WHERE x IN
(SELECT x FROM table WHERE condition);
同じテーブルなので、次のようにトリックアンド実行できます。
UPDATE table SET a=value WHERE x IN
(SELECT * FROM (SELECT x FROM table WHERE condition) as t)
[更新でも削除でも何でも]
これは、テーブル内とその WHERE 句で、同じテーブルのサブクエリを使用して、Priority 列の値が >=1 である場合に、その値を 1 だけ更新して、少なくとも 1 つの行に Priority=1 が含まれていることを確認するために行ったことです (これは、更新実行中にチェックされる条件):
UPDATE My_Table
SET Priority=Priority + 1
WHERE Priority >= 1
AND (SELECT TRUE FROM (SELECT * FROM My_Table WHERE Priority=1 LIMIT 1) as t);
少し見苦しいことは承知していますが、問題なく動作します。
必要な行の ID を一時テーブルに挿入し、そのテーブル内で見つかったすべての行を削除できます。
@Cheekysoft が 2 つのステップで実行するということは、これを意味しているのかもしれません。
によると MySQL UPDATE 構文 @CheekySoft によってリンクされており、一番下に記載されています。
現在、サブクエリでテーブルを更新したり、同じテーブルから選択したりすることはできません。
ユニオンでstore_categoryから選択したまま、store_categoryから削除していると思います。
正面玄関から入って何かがうまくいかない場合は、裏口から入ってください。
drop table if exists apples;
create table if not exists apples(variety char(10) primary key, price int);
insert into apples values('fuji', 5), ('gala', 6);
drop table if exists apples_new;
create table if not exists apples_new like apples;
insert into apples_new select * from apples;
update apples_new
set price = (select price from apples where variety = 'gala')
where variety = 'fuji';
rename table apples to apples_orig;
rename table apples_new to apples;
drop table apples_orig;
これは速い。データは大きいほど良いです。
これを行う最も簡単な方法は、サブクエリ内で親クエリ テーブルを参照するときにテーブル エイリアスを使用することです。
例 :
insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));
これを次のように変更します。
insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));
これを試して
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM (SELECT * FROM STORY_CATEGORY) sc;
Select ステートメントの結果を別の変数に保存し、それを削除クエリに使用してみてください。
このクエリはどうですか?役に立てば幸いです
DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL