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_idproject_id. 통과 한 프로젝트에서 게시물을 삭제하고 싶습니다 client_id.

게시물이 삭제되지 않아 지금 작동하지 않습니다.


10
나는 당신이 요청 한대로 Join을 사용하고 yukondude가 제안한대로 IN 절을 사용하는 것보다 성능이 뛰어 나기 때문에 Yehosef의 대답은 받아 들여야한다고 생각합니다 ...
Gerardo

2
선호되는 패턴은 패턴이 DELETE posts FROM posts JOIN projects ...아니라 IN (subquery)입니다. (Yehosef에서 대답이 바람직한 패턴의 일례를 제공한다.)
spencer7593

@ GerardoGrignoli, 특정 엔진이나 MySQL 버전에서 더 잘 수행됩니까? AFAIK가 동일하기 때문에 두 쿼리가 다르게 수행되어야하는 이유는 없습니다. 내가 가진 경우 물론, 매번 내 쿼리 최적화 니켈은 바보 같은 .... 한
폴 드레이퍼

alias테이블 이름으로 도 사용할 수 있습니다 .
biniam

답변:


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 게시물"대신 "DELETE 게시물에서 게시물 삭제"를 사용해야하기 때문에 정답입니다. 감사!
siannopollo

8
p.project_id에서 내부 조인 프로젝트 (예 : p.project_id ...)에서 'as'방법을 사용할 수 없습니다.
zzapper

14
실제로 조인 된 테이블에는 별칭을 사용할 수 있지만 기본 테이블 (게시물)에는 별칭을 사용할 수 없습니다. "게시물에서 게시물 삭제 INNER JOIN projects p ON p.project_id = posts.project_id"
Weboide


14
한 번의 작업으로 두 테이블 모두에서 삭제할 수도 있기 때문에 이것이 가장 좋은 대답입니다.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_name1table_name2같은 테이블이므로 다음과 같이 작동합니다.

DELETE projects FROM posts INNER JOIN [...]

원하는 경우 두 테이블 모두에서 삭제할 수도 있습니다.

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

참고 order bylimit 멀티 테이블 삭제 작동하지 않습니다 .

또한 테이블의 별명을 선언하는 경우 테이블을 참조 할 때 별명을 사용해야합니다.

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

Carpetsmoker 등의 기여 .


3
더 나은 대답을한다면 적어도 SQL을 더 읽기 쉽게 만들 수 있습니다. 이 질문의 다른 모든 SQL 참조에는 대문자로 된 키워드가 있습니다 (0 표가있는 키워드는 제외). 왜 내 편집 내용을 되돌 렸는지 잘 모르겠습니다.
Yehosef

3
@Yehosef, CAPS가 정말 눈에 띄는 사람들이 있습니다. 나는 내가 유일한 사람이 아니라고 생각합니다. 꽤 많은 사람들이 소문자 스타일을 사용하는 것을 보았습니다.
Pacerier

1
충분히 공평-나는 당신이 좋아하는 스타일로 답을 쓸 수있는 당신의 권리를 존중합니다.)
Yehosef

7
대문자 / 모자없는 토론에 추가하기 위해, 당신이 좋아하는 스타일을 사용할 수 있지만, 대답에서 실제로 편리한 스타일을 혼합하고 있습니다- ON대문자로 표시됩니다. 경험이 부족한 개발자에게는 스타일 측면에서 지저분하고 일관성이없는 것이 좋습니다.
Shade

16
캡스 키워드가 눈에 띄지 않습니다. 그들은 읽을 수있는 쿼리를 만들고있다;)
Sachem

50

또는 약간 다른 (IMO 더 친숙한) 구문으로 같은 것 :

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

BTW, 조인을 사용하는 mysql의 경우 거의 항상 하위 쿼리보다 훨씬 빠릅니다.


사용이란 무엇입니까?
CMCDragonkai


10
@ bigtex777 : SELECT 문에서 USING 키워드는 DELETE 문에서 동일한 키워드와 관련이 없습니다. SELECTs에서는 조인 할 열 목록을 지정하고
DELETEs

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
"사실 당신은 있지만 기본 테이블 (게시물)에, 조인 된 테이블 별칭을 사용할 수있는 'DELETE 게시물 게시물 FROM INNER이 페이지의 p.project_id = posts.project_id 프로젝트를 가입'."- @ Weboide
Jeaf 길버트

2
사실 (인용 dev.mysql.com/doc/refman/5.0/en/delete.html ) "당신이 테이블에 대한 별칭을 선언하면 테이블을 참조 할 때, 당신은 별칭을 사용해야합니다 : T1 AS 테스트에서 삭제 T1, test2 WHERE ... "이므로 별칭을 사용하는 것이 좋습니다.
피터 Bowers

25

나는 이것에 대한 하위 쿼리 솔루션에 더 익숙하지만 MySQL에서는 시도하지 않았습니다.

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

85
하위 쿼리는 일반적으로 작업 속도가 훨씬 느리기 때문에 SQL에서는 IN 키워드를 사용하지 말아야합니다 (일반적으로 초보자에게는 이해하기 쉽지만). 대신 가능하면 JOIN을 사용하십시오.
user276648

14
하위 쿼리에서 많은 수의 행이 반환되면 DB가 충돌하는 경향이 있습니다. 또한 매우 느립니다.
Raj

2
@yukondude 실제로 "IN"은 1 일에 "JOIN"보다 이해하기가 훨씬 쉽기 때문에 SQL에 익숙하지 않은 사람들은 어디서나 "IN"을 작성하는 반면, "JOIN"을 더 잘 사용할 수 있습니다 ( 또는 쿼리에 따라 whooole 훨씬 더 좋습니다). 몇 년 전, 거의 모든 SQL 쿼리가 실제로 좋은 쿼리를 작성하는 방법을 알고있는 누군가가 다시 쓴다는 것을 기억합니다. 그렇기 때문에 "IN"을 피하기 위해 주석을 추가하여 사람들이 가능하면 사용하지 않아야한다는 것을 알았습니다.
user276648

10
내가이 페이지에 온 이유는 내가 IN 문으로 작성한 쿼리가 개가 느리기 때문입니다. 여기에 허용 된 답변을 피하십시오.
MikeKulls 2014 년

4
이 질문이 오래되면 IN 대신 JOIN을 사용해야하는 이유를 아는 것이 중요합니다. where 조건이 행에서 실행될 때 IN 내에서 해당 쿼리를 실행합니다. 즉, 해당 WHERE에 대해 100 개의 행을 점검해야하는 경우 해당 부속 조회가 100 회 실행됩니다. 반면 JOIN은 한 번만 실행됩니다. 따라서 DB가 커질수록 해당 쿼리를 완료하는 데 시간이 오래 걸립니다. @markus는 중요한 것이 아니라고해서 나쁜 코드를 작성해야한다는 의미는 아닙니다. 조금 더 잘 쓰면 앞으로 많은 시간과 두통을 줄일 수 있습니다. :)
RisingSun

11

JOIN을 사용한 MySQL DELETE 레코드

일반적으로 SELECT 문에서 INNER JOIN을 사용하여 다른 테이블에 해당 레코드가있는 테이블에서 레코드를 선택합니다. 또한 INNER JOIN 절을 DELETE 문과 함께 사용하여 테이블에서 레코드를 삭제하고 다른 테이블의 해당 레코드를 삭제할 수 있습니다 (예 : 특정 조건을 만족하는 T1 및 T2 테이블에서 레코드를 삭제하는 경우).

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

DELETE와 FROM 사이에 테이블 이름 T1과 T2를 넣습니다. 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쉼표로 구분 된 목록으로 뒤에 테이블 이름을 지정해야 합니다.

당신은 모든 세 개의 테이블 (에서 항목을 삭제하려는 가정 posts, projects, clients특정 클라이언트에 대한) :

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

7

아래처럼 시도하십시오 :

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

4

서브을 사용하여 삭제하는 또 다른 방법은 그 사용하는 것보다 더 나은 선택 IN이 될 것입니다WHERE EXISTS

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

조인 대신 이것을 사용하는 한 가지 이유는 DELETEwith를 JOIN사용 하는 것을 금지하기 때문입니다 LIMIT. 전체 테이블 잠금을 생성하지 않도록 블록을 삭제하려는 LIMIT경우이 DELETE WHERE EXISTS방법을 사용하여 추가 할 수 있습니다 .


1
이 쿼리를 "별칭"으로 쓸 수 있습니까? postsEXISTS () 내 posts에서 행이 삭제되는 것과 동일한 방법이 구문에서 명확하지 않습니다 . (IMHO 어쨌든)
MattBianco

들리지만 테이블에서 별칭을 삭제할 수 없습니다. 하위 쿼리의 "게시물"은 전체 테이블 이름이어야합니다. 즉, 하위 선택 From 절에서 해당 테이블을 재사용하려면 별칭을 지정해야합니다.
Jim Clouse

1
이것은 작동합니다 :DELETE p FROM posts p WHERE EXISTS ( SELECT 1 FROM projects WHERE projects.client_id = p.client_id);
MattBianco

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);

하나의 테이블에서 DELETE 레코드 :

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

두 테이블 모두에서 레코드 삭제

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

1

가입이 작동하지 않으면이 솔루션을 사용해보십시오. 외래 키 + 특정 위치 조건을 사용하지 않을 때 t1에서 고아 레코드를 삭제하기위한 것입니다. 즉, "code"필드가 비어 있고 "name"필드와 일치하는 table2에 레코드가없는 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.