MySQL“NOT IN”쿼리


181

Table1다른 테이블 ( Table2) 의 열에 주요 열 값이없는 곳의 모든 행을 던지기 위해 간단한 쿼리를 실행하고 싶었습니다 .

나는 다음을 사용하려고 시도했다.

SELECT * FROM Table1 WHERE Table1.principal NOT IN Table2.principal

대신 구문 오류가 발생합니다. 구글 검색을 통해 사람들이 MySQL을 지원하지 않으며 NOT IN매우 복잡한 것을 사용해야하는 포럼으로 이끌었습니다 . 이것이 사실입니까? 아니면 끔찍한 실수를 저지르고 있습니까?


1
세 개의 테이블에서 유사한 데이터를 원한다면 어떻게해야합니까? 하나의 table1에 2000 개의 항목이 있고 다른 두 개의 테이블 2 & 3에는 각각 500 개의 항목이 있으며 모두 공통 필드 'name'이 있습니다. 'name'을 기준으로 table2 & 3에없는 표 1에서 모든 세부 사항을 얻는 방법은 무엇입니까? 그렇다면 NOT IN을 두 번 사용할 수 있습니까?

답변:


310

IN을 사용하려면 세트가 있어야합니다. 대신이 구문을 사용하십시오.

SELECT * FROM Table1 WHERE Table1.principal NOT IN (SELECT principal FROM table2)

85
table2.principal수있을 때 조심하십시오 NULL. 이 경우 NOT IN항상 돌아갑니다 FALSE때문이 NOT IN로 처리됩니다 <> ALL같은 하위 쿼리의 모든 행과 비교하는 Table1.principal <> table2.principal과 비교했을 때 실패 NULL: Table1.principal <> NULL발생하지 않습니다 TRUE. 수정하려면 : NOT IN (SELECT principal FROM table2 WHERE principal IS NOT NULL).
Basti

4
의견 @Basti에 감사드립니다! 쿼리가 예상대로 작동하지 않는 이유를 이해하려고 많은 시간을 보냈습니다.
gvas

3
'NOT IN'목록에서 'SELECT *'를 사용하지 마십시오. 특정 열을 선택해야합니다. 그렇지 않으면이 오류가 발생합니다 : stackoverflow.com/questions/14046838/…
Lorien Brune

165

하위 쿼리 옵션은 이미 답변되었지만 대부분의 LEFT JOIN경우이 작업을 수행하는 더 빠른 방법 일 수 있습니다.

SELECT table1.*
FROM table1 LEFT JOIN table2 ON table2.principal=table1.principal
WHERE table2.principal IS NULL

SRKR의 의견과 같이 여러 테이블을 확인하여 테이블에 없는지 확인하려면 다음을 사용할 수 있습니다.

SELECT table1.*
FROM table1
LEFT JOIN table2 ON table2.name=table1.name
LEFT JOIN table3 ON table3.name=table1.name
WHERE table2.name IS NULL AND table3.name IS NULL

2
내 테스트에서 NOT IN& 모두 동일한 성능을 보였습니다 LEFT JOIN. +1 둘 다
BufferStack

쿼리가 한 번 실행되면 내부 DB 캐싱으로 인한 결과에 상관없이 동일한 결과를 얻을 수 있습니다.
Toote

나에게 성능은 나아졌다. 외래 키가 설정되어있는 동안 다른 테이블을 통과했습니다.
Keenora Fluffball

36

NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL in MySQL

MySQL과 SQL Server를 제외한 다른 모든 시스템 은 일치하는 값을 찾 자마자 최적화 LEFT JOIN/IS NULL 반환 할 수 FALSE있으며이 동작을 문서화 한 유일한 시스템입니다. […] MySQL은 알고리즘 을 사용 HASH하고 MERGE결합 할 수 없기 때문에 유일 ANTI JOIN하게 가능한 것은NESTED LOOPS ANTI JOIN

[…]

본질적으로, [ NOT IN] 는 이 계획들이 서로 다른 코드의 분기에 의해 실행되고 결과에서 다르게 보인다는 사실에도 불구하고 LEFT JOIN/ IS NULL사용 과 정확히 같은 계획 입니다 EXPLAIN. 알고리즘은 실제로 동일하며 쿼리는 동시에 완료됩니다.

[…]

이 하락은 선형이며 두 필드가 모두 색인화되어있는 한 데이터 분산, 두 테이블의 값 수 등에 의존하지 않는 것이므로 [사용시 성능 저하 NOT EXISTS]의 정확한 이유를 말하기는 어렵습니다 . MySQL에는 본질적으로 하나의 작업을 수행하는 세 가지 코드가 있기 때문에 책임이있는 코드 EXISTS는 추가 시간이 걸리는 추가 검사를 수행 할 수 있습니다.

[…]

MySQL은 세 가지 방법을 모두 최적화하여 일종의 작업을 수행 할 수 있습니다 NESTED LOOPS ANTI JOIN. […] 그러나이 세 가지 방법은 세 가지 다른 코드 조각으로 실행되는 세 가지 다른 계획을 생성합니다. EXISTS술어 를 실행하는 코드 는 약 30 % 덜 효율적입니다 […]

그렇기 때문에 MySQL에서 결 측값을 검색 하는 가장 좋은 방법은 LEFT JOIN/ IS NULL또는 NOT IN대신을 사용하는 것 NOT EXISTS입니다.

(단계 추가)


7

불행히도 "NOT IN"절의 MySql 사용에 문제가있는 것 같습니다. 아래의 스크린 샷은 잘못된 결과를 반환하는 하위 쿼리 옵션을 보여줍니다.

mysql> show variables like '%version%';
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 1.1.8                        |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| version                 | 5.5.21                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
7 rows in set (0.07 sec)

mysql> select count(*) from TABLE_A where TABLE_A.Pkey not in (select distinct TABLE_B.Fkey from TABLE_B );
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.07 sec)

mysql> select count(*) from TABLE_A left join TABLE_B on TABLE_A.Pkey = TABLE_B.Fkey where TABLE_B.Pkey is null;
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> select count(*) from TABLE_A where NOT EXISTS (select * FROM TABLE_B WHERE TABLE_B.Fkey = TABLE_A.Pkey );
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> 

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.