하위 쿼리를 조건으로 사용하는 MySQL DELETE 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/956397 다음에 테이블 별칭을 추가하기 만하면됩니다.DELETE t FROM table t ...
PiTheNumber

답변:


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

:) 그것을 봐 주셔서 감사합니다 - 그래, 하위 쿼리를 통해 삭제 MySQL의 현재 수없는 것
mikl

마지막 줄에있는 "DELETE FROM term_hierarchy AS th"가 동일한 문제를 가지고 있지 않습니까? OP와 동일한 구문 오류가 발생합니다.
malhal

term_hierarchy_backup.tid에 색인을 추가해야합니다.
Roman Newaza

1
나는 MariaDB 10.3.14 또는 MySQL의 커뮤니티 서버 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 FROM tableE)에 의해 생성 된 임시 테이블의 별칭입니다. WHERE arg = 1 AND foo = 'bar') "입니다.
Tilman Hausherr

3
왜 이것이 작동합니까? 이것은 나에게 많이 바뀌지 만 더 이상 작동하지 않아야합니다. 그것은 않는 일을하지만, 안.
donatJ 2014

1
믿을 수 없는. 이것은 실제로 작동합니다! 그러나 e ...로 테이블의 별칭을 지정하지 않아도됩니다. 원하는 별칭을 사용할 수 있습니다.
Andrei Sandulescu 2014

1
@jakabadambalazs 내 이유는 "SELECT id"로 시작하는 하위 쿼리가 완료되고 ID 목록을 반환하므로 삭제하려는 테이블의 잠금을 해제한다는 것입니다.
CodeReaper

9
@jakabadambalazs : eDELETE와 하위 SELECT에서 동일한 테이블 ( )을 사용할 수 없습니다 . 우리는 할 수 있습니다 , 그러나 임시 테이블 (만들기 위해 하위 하위 SELECT를 사용 x), 및 사용을 하위 SELECT 위해.
Steve Almond

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

10

다음과 같이 delete 문에서 별칭을 다시 참조해야합니다.

DELETE th FROM term_hierarchy AS th
....

여기 MySQL 문서에 설명되어 있습니다.


별칭에 관한 것이 아닙니다. OP를 다시 확인하십시오
ajreal

@ajreal-그랬습니다. 오류가 별칭 정의에서 시작되며 MySQL 문서에는 DELETE 문과 FROM 절에서 별칭을 사용해야한다고 명시 적으로 명시되어 있습니다. 그래도 반대표에 감사드립니다.
JNK

단순히이 할 delete from your_table as t1 where t1.id in(select t2.id from your_table t2);당신이 무엇을 얻었 는가?
ajreal

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
Björn

1
별칭을 수정할 필요가 없습니다. 삭제시 선택할 대상 테이블을 지정하지 마십시오. 이것이 진짜 문제입니다
ajreal

7

나는 이것에 약간 다른 방식으로 접근했고 그것은 나를 위해 일했습니다.

더 이상 조건 행이 더 이상 남아 있지 않은 secure_links테이블을 참조하는 conditions테이블에서 제거해야했습니다 . 기본적으로 하우스 키핑 스크립트입니다. 이로 인해 오류가 발생했습니다. 삭제할 대상 테이블을 지정할 수 없습니다.

그래서 영감을 얻기 위해 여기에서 아래 쿼리를 생각 해냈고 잘 작동합니다. 이는 sl1DELETE에 대한 참조로 사용되는 임시 테이블 을 생성하기 때문 입니다.

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"절이 아닙니까? 하위 쿼리에서 많은 수의 값이 반환되는 경우 극히 비효율적 인 곳은 어디입니까? 삭제할 ID의 하위 쿼리에서 원래 테이블에 대해 "in (subquery)"대신 내부 (또는 오른쪽) 조인을하지 않는 이유가 확실하지 않습니다.?

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에서 조인으로 삭제 하면 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 )

하나의 쿼리로이 작업을 수행 할 수 있지만 이것이 제가 선호하는 것입니다.


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 문에서 별칭을 사용할 수 있습니다.

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.