MySQL 하위 쿼리 문제


16

이 쿼리가 왜

DELETE FROM test 
WHERE id = ( SELECT id 
             FROM (SELECT * FROM test) temp 
             ORDER BY RAND() 
             LIMIT 1
           );

때로는 1 행, 때로는 2 행, 때로는 아무것도 삭제하지 않습니까?

이 양식으로 작성하면 :

SET @var = ( SELECT id 
             FROM (SELECT * FROM test) temp 
             ORDER BY RAND() 
             LIMIT 1
           ); 
DELETE FROM test 
WHERE id=@var;

그런 다음 제대로 작동합니다-하위 쿼리에 문제가 있습니까?

답변:


13

첫 번째 쿼리가 일관되게 작동하지 않는 이유는 MySQL이 하위 쿼리를 처리하는 방법과 관련이 있습니다. 실제로 하위 쿼리는 다시 쓰기와 변환을 경험하게됩니다 .

여기에 설명 된 네 가지 구성 요소가 있습니다.

  • Item_in_optimizer
  • Item_in_subselect
  • Item_ref
  • Left_expression_Cache

게시 된 예에서 item_ref가 자체 참조가되도록하는 것은 불가능합니다. 단일 DELETE 쿼리와 관련하여 일부 키는 변환 중에 사용 가능하고 일부는 그렇지 않으므로 테스트 테이블 전체를 자체적으로 자체 참조 할 수는 없습니다. 따라서 쿼리에서 자체 참조를 수행하면 실제 자체 참조 테이블에 키가 있어도 키 (이 경우 id)가 변환에서 사라질 수 있습니다.

MySQL 하위 쿼리는 하위 SELECT에만 유용하며 테이블을 여러 번 자체 참조하는 경우에도 마찬가지입니다. 비 SELECT 쿼리에 대해서도 마찬가지입니다.

이 설명이 도움이되기를 바랍니다.


7

예상대로 작동하지 않는 이유는 MySQL이 하위 쿼리를 처리하는 방법이 아니라 MySQL이 UPDATE명령문을 처리하는 방법 때문이라고 생각합니다 . 진술 :

DELETE 
FROM test 
WHERE id = 
      ( SELECT id 
        FROM 
            ( SELECT * 
              FROM test
            ) temp 
        ORDER BY RAND() 
        LIMIT 1
      ) 

WHERE조건을 행별로 처리합니다 . 즉, 모든 행에 대해 하위 쿼리를 실행하고 id다음 에 대해 결과를 테스트합니다 .

  ( SELECT id 
    FROM 
        ( SELECT * 
          FROM test
        ) temp 
    ORDER BY RAND() 
    LIMIT 1
  ) 

따라서 때로는 0, 1, 2 또는 그 이상의 행과 일치하고 삭제됩니다!


다음과 같이 다시 작성할 수 있으며 하위 쿼리가 한 번 처리됩니다.

DELETE t
FROM 
      test t
  JOIN 
      ( SELECT id 
        FROM test  
        ORDER BY RAND() 
        LIMIT 1
      ) tmp
    ON tmp.id = t.id

1

에 첫 번째 글 머리 기호에서 이 페이지 , LIMITMySQL은 서브 쿼리에서 지원되지 않습니다. 그래도 왜 오류가 발생하지 않는지 잘 모르겠습니다.


2
LIMIT사용하는 경우에만 지원되지 않습니다 IN (~ drachenstern 역 따옴표로 대체 <코드>)
tomas.lang

글쎄 ... 나는 뭔가를 배웠는데 왜 오류가 발생하지 않았는지 설명합니다!
데릭 다우니

@ tomas.lang <code> 블록 대신 단어 주위에`(틱 표시)를 사용할 수 있습니다.
데릭 다우니
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.