739

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'を指定できません

どうすればこれを克服できますか?

4

16 に答える 16

871

更新:この回答は、一般的なエラー分類を対象としています。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';

コメントでこのアドバイスをしてくれたPeterV.Mørchに感謝します。

テクニックの例は、もともとNabbleで公開されたバロンシュワルツのもので、ここで言い換えて拡張したものです。

于 2008-09-05T10:07:48.143 に答える
439

NexusRexは、同じテーブルから結合して削除するための非常に優れたソリューションを提供しました。

これを行う場合:

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 番目のクエリは派生マージの最適化に適していません。したがって、オプティマイザは最初にサブクエリを実行するよう強制されます。

于 2012-03-23T17:23:55.737 に答える
112

最近、同じテーブルのレコードを更新する必要がありました。以下のようにしました。

UPDATE skills AS s, (SELECT id  FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development' 
WHERE s.id = p.id;
于 2012-10-04T23:39:44.387 に答える
111

サブクエリinner join内のは不要です。テーブルstory_categorycategory_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);
于 2009-06-03T21:40:18.830 に答える
40
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
)
于 2011-12-23T20:03:08.740 に答える
15

これは、少なくとも 1 つの行に Priority=1 が含まれていることを確認するために、同じテーブルのサブクエリを使用してテーブルとその WHERE 句で >=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);

少し醜いことは知っていますが、うまく機能します。

于 2010-09-02T07:31:45.660 に答える
5

目的の行のIDを一時テーブルに挿入してから、そのテーブルで見つかったすべての行を削除できます。

これは、@Cheekysoftが2つのステップでそれを行うことによって意味したことかもしれません。

于 2008-09-05T10:25:35.383 に答える
3

@CheekySoft によってリンクされた Mysql UPDATE Syntaxによると、一番下に表示されます。

現在、サブクエリでテーブルを更新して同じテーブルから選択することはできません。

ユニオンでまだ選択している間に store_category から削除していると思います。

于 2015-01-08T13:18:46.740 に答える
2

何かがうまくいかない場合は、正面玄関から入ってから、裏口に入ります。

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;

これは速い。データが大きければ大きいほどよい。

于 2009-03-29T02:26:30.380 に答える
2

Select ステートメントの結果を別の変数に保存してから、それを削除クエリに使用してみてください。

于 2016-05-31T11:35:18.000 に答える