条件としてサブクエリを使用したMySQLDELETE FROM


85

私はこのようなクエリを実行しようとしています:

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015
);

おそらくおわかりのように、同じtidに他の親がある場合は、1015への親関係を削除したいと思います。ただし、構文エラーが発生します。

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS th
WHERE th.parent = 1015 AND th.tid IN (
  SELECT DISTINCT(th1.tid)
  FROM ter' at line 1

ドキュメントを確認し、サブクエリを単独で実行しましたが、すべて確認できたようです。誰かがここで何が悪いのか理解できますか?

更新:以下で回答するように、MySQLは、削除するテーブルを条件のサブクエリで使用することを許可していません。


2
注意:一番下にある良い答えstackoverflow.com/a/4471359/956397DELETE t FROM table t ...
PiTheNumber 2014

回答:


38

削除対象のテーブルを指定することはできません。

回避策

create table term_hierarchy_backup (tid int(10)); <- check data type

insert into term_hierarchy_backup 
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015;

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (select tid from term_hierarchy_backup);

私たちは両方とも正しいです-以下の私の答えに対する彼のコメントを参照してください。エイリアスの構文とロジックは両方とも問題でした:)
JNK 2010

ええ、サブクエリを介した削除は現在MySQLでは不可能なようです–それを見てくれてありがとう:)
mikl 2010

その最後の行の「DELETEFROMterm_hierarchy AS th」にも同じ問題はありませんか?OPと同じ構文エラーが発生します。
malhal 2012年

term_hierarchy_backup.tidにインデックスを追加する必要があります。
ローマンニューアザ2013年

1
私はそれがMariaDB 10.3.14やMySQL Community Serverの5.7.27に2019年でもないことが可能であることが、そのことを確認することができています
alpham8

283

サブクエリの使用中にこの質問を削除しようとしている他の人のために、MySQLをアウトスマートにするためにこの例を残します(一部の人々はそれができないと思っているようですが):

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM tableE
             WHERE arg = 1 AND foo = 'bar');

エラーが発生します:

ERROR 1093 (HY000): You can't specify target table 'e' for update in FROM clause

ただし、このクエリ:

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM (SELECT id
                   FROM tableE
                   WHERE arg = 1 AND foo = 'bar') x);

正常に動作します:

Query OK, 1 row affected (3.91 sec)

サブクエリを追加のサブクエリ(ここではxという名前)でラップすると、MySQLはあなたが求めることを喜んで実行します。


10
少し時間がかかりましたが、動作しました。重要:1)最初のテーブルは、ここに示すように「e」でエイリアスする必要があります。2)末尾の「x」はプレースホルダーではなく、サブクエリ「(SELECT id FROMtableE」によって生成される一時テーブルのエイリアスです。 WHERE arg = 1 AND foo = 'bar') "。
Tilman Hausherr 2013年

3
なぜこれが機能するのですか?これは私にとって大きな変化ですが、さらに、うまくいかないはずです。それ機能しますが、機能しないはずです。
donatJ 2014

1
信じられない。これは実際に機能します!ただし、テーブルのエイリアスをeで強制する必要はありません...任意のエイリアスを使用できます。
Andrei Sandulescu 2014

1
@jakabadambalazsそれを思いついたときの私の推論は、「SELECT id」で始まるサブクエリが終了し、IDのリストを返すため、削除するテーブルのロックを解放するというものでした。
codeReaper 2014

9
@jakabadambalazs:eDELETEとそのサブSELECTで同じテーブル()を使用することはできません。我々はできる、しかし、(一時テーブルを作成するために、サブサブSELECTを使用x)、および使用そのサブSELECTのために。
スティーブアーモンド

39

DELETEキーワードの後にエイリアスを含める必要があります。

DELETE th
FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN 
(
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015
);

3
これは良い答えです。適切なエイリアシングは、元の投稿と同様の問題を解決するのに大いに役立ちます。(私のように。)
usumoio 2013

10

次のように、deleteステートメントでエイリアスを再度参照する必要があります。

DELETE th FROM term_hierarchy AS th
....

ここMySQLドキュメントで概説されているように。


エイリアスに関するものではありません。OPをもう一度確認してください
ajreal 2010

@ ajreal-私はそうしましたが、エラーはエイリアス定義から始まり、MySQLのドキュメントには、DELETEステートメントとFROM句でエイリアスを使用する必要があると明示的に記載されています。しかし、反対票をありがとう。
JNK 2010

単にこれをdelete from your_table as t1 where t1.id in(select t2.id from your_table t2);あなたは何を得ましたか?
ajreal 2010

4
ドキュメントには明確に記載されています。Currently, you cannot delete from a table and select from the same table in a subquery. dev.mysql.com/doc/refman/5.5/en/delete.html
ビョルン

1
エイリアスを修正する必要はありません。削除で選択するターゲットテーブルを指定しないでください...これが本当の問題です
ajreal 2010

7

私は少し異なる方法でこれにアプローチしました、そしてそれは私のために働きました。

条件行が残っていないsecure_linksテーブルを参照しているテーブルから削除する必要conditionsがありました。基本的にハウスキーピングスクリプト。これにより、エラーが発生しました-削除するターゲットテーブルを指定できません。

そこで、ここでインスピレーションを探して、以下のクエリを思いつきました。それは問題なく機能します。これはsl1、DELETEの参照として使用される一時テーブルを作成するためです。

DELETE FROM `secure_links` WHERE `secure_links`.`link_id` IN 
            (
            SELECT
                `sl1`.`link_id` 
            FROM 
                (
                SELECT 

                    `sl2`.`link_id` 

                FROM 
                    `secure_links` AS `sl2` 
                    LEFT JOIN `conditions` ON `conditions`.`job` = `sl2`.`job` 

                WHERE 

                    `sl2`.`action` = 'something' AND 
                    `conditions`.`ref` IS NULL 
                ) AS `sl1`
            )

私のために働きます。


5

削除の「in」句は...サブクエリから返される値が多数ある場合、非常に非効率的ではありませんか?「in(サブクエリ)」ではなく、削除するIDのサブクエリから元のテーブルに対して内部(または右)結合だけを行わない理由がわかりません。

DELETE T FROM Target AS T
RIGHT JOIN (full subquery already listed for the in() clause in answers above) ` AS TT ON (TT.ID = T.ID)

そして、「MySQLはそれを許可していません」で答えられるかもしれませんが、それは私にとっては問題なく動作しています。 MySQLのJoinで削除すると、DELETE / JOINの問題が明確になります


2

2つのクエリでこれを実行する場合は、いつでも次のようなことを実行できます。

1)テーブルからIDを取得します。

SELECT group_concat(id) as csv_result FROM your_table WHERE whatever = 'test' ...

次に、マウス/キーボードまたはプログラミング言語を使用して結果を以下のXXXにコピーします。

2) DELETE FROM your_table WHERE id IN ( XXX )

1つのクエリでこれを実行できるかもしれませんが、これが私が好むものです。


0

@ CodeReaper、@ BennyHill:期待どおりに機能します。

ただし、テーブルに数百万の行があると時間の複雑さが増すのではないでしょうか。どうやら、それは約かかりました5ms正しくインデックス付けされたテーブルに5kのレコードがあるために実行するました。

私の質問:

SET status = '1'
WHERE id IN (
    SELECT id
    FROM (
      SELECT c2.id FROM clusters as c2
      WHERE c2.assign_to_user_id IS NOT NULL
        AND c2.id NOT IN (
         SELECT c1.id FROM clusters AS c1
           LEFT JOIN cluster_flags as cf on c1.last_flag_id = cf.id
           LEFT JOIN flag_types as ft on ft.id = cf.flag_type_id
         WHERE ft.slug = 'closed'
         )
      ) x)```

Or is there something we can improve on my query above?

0

削除ステートメントでこのようにエイリアスを使用できます

DELETE  th.*
FROM term_hierarchy th
INNER JOIN term_hierarchy th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th.parent = 1015;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.