MySQLの結合で削除


501

これが、テーブルを作成するスクリプトです。

CREATE TABLE clients (
   client_i INT(11),
   PRIMARY KEY (client_id)
);
CREATE TABLE projects (
   project_id INT(11) UNSIGNED,
   client_id INT(11) UNSIGNED,
   PRIMARY KEY (project_id)
);
CREATE TABLE posts (
   post_id INT(11) UNSIGNED,
   project_id INT(11) UNSIGNED,
   PRIMARY KEY (post_id)
);

PHPコードで、クライアントを削除するときに、すべてのプロジェクトの投稿を削除したいと思います。

DELETE 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;

投稿テーブルは外部キーを持っていないclient_idだけで、project_id。合格したプロジェクトの投稿を削除したいclient_id

削除された投稿がないため、現在これは機能していません。


10
私は...彼はあなたが尋ねたとyukondudeが提案されているとして、それがより良いIN句を使用するよりも実行していることとして参加使っているのでYehosefの答えは、受け入れられたものであるべきだと思う
ヘラルドGrignoli

2
推奨されるパターンは、パターンではDELETE posts FROM posts JOIN projects ...なくですIN (subquery)。(Yehosefからの回答は、優先パターンの例を示しています。)
spencer7593

@GerardoGrignoli、それはMySQLの特定のエンジンまたはバージョンでより良いパフォーマンスを発揮しますか?2つのクエリはまったく同じであるため、2つのクエリの実行方法が異なる理由はありません。もちろん、クエリオプティマイザーが毎回バカなことをするたびにニッケルを使用していたとしたら...
Paul Draper

aliasテーブル名に使用してそれを使用することもできます。
ビニアム2016

回答:


1254

postsテーブルからエントリを削除することを指定するだけです。

DELETE posts
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

編集:詳細については、この代替回答を見ることができます


117
削除するテーブルが明確になるため、結合では通常の「DELETE FROM posts」の代わりに「DELETE posts FROM posts」を使用する必要があるため、これが正しい答えであることに注意してください。ありがとう!
siannopollo

8
ここでは「as」メソッドを使用できないことに注意してください。たとえば、p.project_idのpとしての内部結合プロジェクト...
zzapper

14
実際には、結合されたテーブルにはエイリアスを使用できますが、メインテーブル(投稿)には使用できません。"投稿を削除します。投稿INNER JOINプロジェクトから投稿p ON p.project_id = posts.project_id"
Weboide


14
1つのアクションで両方のテーブルから削除することもできるため、これが最良の答えですDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium

84

複数のテーブルを選択しているので、削除するテーブルは明確になりました。選択する必要があります

DELETE posts FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

この場合、table_name1およびtable_name2同じテーブルがあるので、これは動作します:

DELETE projects FROM posts INNER JOIN [...]

必要に応じて、両方のテーブルから削除することもできます。

DELETE posts, projects FROM posts INNER JOIN [...]

ことを注意order byし、limit マルチテーブルの削除には使用できません

また、テーブルのエイリアスを宣言する場合は、テーブルを参照するときにエイリアスを使用する必要があることに注意してください。

DELETE p FROM posts as p INNER JOIN [...]

Carpetsmokerなどからの寄稿


3
あなたがより良い答えをしているなら-少なくともあなたはSQLをより読みやすくすることができます。この質問の他のすべてのSQL参照には、大文字のキーワードがあります(投票数が0のキーワードを除く)。編集内容を元に戻した理由がわかりません。
Yehosef 2015

3
@ Yehosef、CAPSが本当に目立つ人のグループがあります。私は私だけではないと思います。かなりの数の人が小文字のスタイルを採用するのを見てきました。
ペーチェリエ2015

1
十分に公正-私はあなたがあなたの好きなスタイルであなたの答えを書くあなたの権利を尊重します;)
Yehosef '13

7
キャップ/キャップなしのディスカッションに追加するには、本当、好きなスタイルを使用できますが、答えでは、実際に便利なスタイルを混在させています- ON大文字です。経験の浅い開発者にとっては、面倒でスタイルの点で一貫性がないことが問題ではないかもしれません。
シェード

16
CAPSキーワードは明白ではありません。彼らは質問を読めるようにしている;)
Sachem

50

または同じことで、わずかに異なる(IMOフレンドリー)構文を使用します。

DELETE FROM posts 
USING posts, projects 
WHERE projects.project_id = posts.project_id AND projects.client_id = :client_id;

ところで、結合を使用するmysqlでは、ほとんどの場合、サブクエリよりも高速です...


USINGの意味?
CMCDragonkai 2015年


10
@ bigtex777:SELECTステートメントのキーワードUSINGは、DELETEステートメントの同じキーワードとはほとんど関係がないことに注意してください。SELECTでは、結合する列のリストを指定しますが、DELETEでは、結合のすべてのテーブルのリストです
ivanhoe

42

このようなALIASを使用することもできます。これは、私のデータベースで使用するだけで機能します。tはテーブルを削除する必要があります!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id

1
これは、テーブル名の重複を避けるために複合キー結合で役立ちます
Marquez

1
「実は、あなたが参加したテーブルのエイリアスを使用することができますが、ないメインテーブル用(ポスト) 『ポストINNER FROM DELETE投稿がプロジェクトに参加P ON p.project_id = posts.project_id』。」 - @ Weboide
Jeafギルバート

2
実際(dev.mysql.com/doc/refman/5.0/en/delete.htmlから引用)「テーブルのエイリアスを宣言する場合、テーブルを参照するときにエイリアスを使用する必要があります。DELETE t1 FROM test AS t1 test2 WHERE ... "したがって、エイリアスの使用は問題ありません。
Peter Bowers、2015

25

私はこれに対するサブクエリソリューションに慣れていますが、MySQLでは試していません。

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );

85
SQLではINキーワードを使用しないでください(初心者にとっては通常は簡単ですが)。代わりに(可能な場合)JOINを使用してください。サブクエリは通常、処理が非常に遅くなるためです。
user276648 '28 / 10/28

14
これは、サブクエリによって返された行の数が非常に多い場合に、DBをクラッシュさせる傾向があります。また、非常に遅いです。
Raj

2
@yukondude確かに "IN"は、最初は "JOIN"よりもはるかに理解しやすいので、SQLに慣れていない人は、どこでも "IN"と書いてしまいます。またはクエリに応じて、より良いwhooole)。数年前、私はSQLクエリのほとんどすべてを、実際に優れたクエリの作成方法を知っている人が書き直したことを覚えています。「IN」を避けるためにコメントを追加したのはそのためです。そうすることで、人々は可能であればそれを使用しないようにする必要があることを知っています。
user276648 2012年

10
私がこのページにアクセスした理由は、INステートメントを使用して記述したクエリが非常に遅いためです。ここで受け入れられた答えは絶対に避けてください。
MikeKulls 2013年

4
この質問と同じくらい古いので、INではなくJOINを使用する必要がある理由を理解することが重要です。条件が行で実行されると、IN内でそのクエリが実行されます。つまり、そのWHEREに対してチェックする必要のある100行がある場合、そのサブクエリは100回実行されます。一方、JOINはONCEのみを実行します。そのため、dbがどんどん大きくなると、そのクエリが完了するまでに時間がかかります。@markus何かが重要ではないからといって、悪いコードを書くべきではありません。少し上手に書けば、将来の多くの時間と頭痛を節約できます。:)
RisingSun 2015年

11

JOINを使用したMySQL DELETEレコード

通常、SELECTステートメントでINNER JOINを使用して、他のテーブルに対応するレコードがあるテーブルからレコードを選択します。また、DELETEステートメントでINNER JOIN句を使用して、テーブルからレコードを削除したり、他のテーブルの対応するレコードを削除したりできます。たとえば、特定の条件を満たすT1テーブルとT2テーブルの両方からレコードを削除するには、次のステートメントを使用します。

DELETE T1, T2
FROM T1
INNER JOIN T2 ON T1.key = T2.key
WHERE condition

テーブル名T1とT2をDELETEとFROMの間に置いていることに注意してください。T1テーブルを省略すると、DELETEステートメントはT2テーブルのレコードのみを削除し、T2テーブルを省略すると、T1テーブルのレコードのみが削除されます。

結合条件T1.key = T2.keyは、削除する必要があるT2テーブルの対応するレコードを指定します。

WHERE句の条件は、削除する必要があるT1およびT2のレコードを指定します。


11

単一テーブルの削除:

postsテーブルからエントリを削除するには:

DELETE ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

projectsテーブルからエントリを削除するには:

DELETE pj 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

clientsテーブルからエントリを削除するには:

DELETE C
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

複数のテーブルの削除:

結合した結果から複数のテーブルからエントリを削除するには、DELETEコンマ区切りのリストとしてテーブル名を指定する必要があります。

あなたはすべての3つのテーブル(からエントリを削除したいとしpostsprojectsclients特定のクライアント用):

DELETE C,pj,ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id


4

サブを使用して削除する別の方法は、それがより優れているの選択INだろうWHERE EXISTS

DELETE  FROM posts
WHERE   EXISTS ( SELECT  1 
                 FROM    projects
                 WHERE   projects.client_id = posts.client_id);

結合の代わりにこれを使用する1つの理由は、DELETEwith JOINがの使用を禁止することですLIMIT。完全なテーブルロックを生成しないようにブロック単位で削除する場合は、LIMITこのDELETE WHERE EXISTSメソッドを使用して追加できます。


1
このクエリは「エイリアス」で記述できますか?構文から、postsEXISTS()内でposts行が削除されるのとEXISTS()がどのように同じであるかは明確ではありません。(とにかく私見)
MattBianco 2014年

聞きましたが、テーブルでのエイリアスの削除は許可されていません。サブクエリの「投稿」は完全なテーブル名である必要があります。つまり、そのテーブルをsub-select From句で再利用する場合は、そこにエイリアスを設定する必要があります。
Jim Clouse 2014年

1
これは機能します:DELETE p FROM posts p WHERE EXISTS ( SELECT 1 FROM projects WHERE projects.client_id = p.client_id);
MattBianco 2014年

4
mysql> INSERT INTO tb1 VALUES(1,1),(2,2),(3,3),(6,60),(7,70),(8,80);

mysql> INSERT INTO tb2 VALUES(1,1),(2,2),(3,3),(4,40),(5,50),(9,90);

1つのテーブルからレコードを削除:

mysql> DELETE tb1 FROM tb1,tb2 WHERE tb1.id= tb2.id;

両方のテーブルからレコードを削除します。

mysql> DELETE tb2,tb1 FROM tb2 JOIN tb1 USING(id);

1

参加できない場合は、この解決策を試してください。外部キーを使用していないときにt1から孤立したレコードを削除するためのものであり、特定のwhere条件です。つまり、フィールド "コード"が空で、テーブル "2"にレコードがなく、フィールド "名前"で一致するレコードをtable1から削除します。

delete table1 from table1 t1 
    where  t1.code = '' 
    and 0=(select count(t2.name) from table2 t2 where t2.name=t1.name);

0

これを試して、

DELETE posts.*
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

-3

-削除が必要なテーブルではエイリアスを使用できないことに注意してください

DELETE tbl_pagos_activos_usuario
FROM tbl_pagos_activos_usuario, tbl_usuarios b, tbl_facturas c
Where tbl_pagos_activos_usuario.usuario=b.cedula
and tbl_pagos_activos_usuario.cod=c.cod
and tbl_pagos_activos_usuario.rif=c.identificador
and tbl_pagos_activos_usuario.usuario=c.pay_for
and tbl_pagos_activos_usuario.nconfppto=c.nconfppto
and NOT ISNULL(tbl_pagos_activos_usuario.nconfppto)
and c.estatus=50
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.