한 테이블에서 다른 테이블에 존재하지 않는 모든 레코드를 선택하는 방법은 무엇입니까?


469

table1 (ID, 이름)
table2 (ID, 이름)

질문:

SELECT name   
FROM table2  
-- that are not in table1 already

답변:


843
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL

Q : 여기서 무슨 일이 일어나고 있습니까?

A : 개념적으로 우리는 모든 행을 선택하고 table1각 행에 대해 table2동일한 name열 값을 가진 행을 찾습니다 . 그러한 행이 없으면 table2해당 행에 대해 결과 부분을 비워 둡니다 . 그런 다음 일치하는 행이 존재하지 않는 결과에서 해당 행만 선택하여 선택을 제한합니다. 마지막으로, name열을 제외하고 결과의 모든 필드를 무시합니다 table1.

모든 경우에 가장 성능이 좋은 방법은 아니지만 기본적으로 ANSI 92 SQL 을 구현하려는 모든 데이터베이스 엔진에서 작동해야합니다.


16
@ Z-보스 : 그것은 SQL Server에서 가장 성능이 좋은이기도 : explainextended.com/2009/09/15/...
OMG 조랑말

7
@BunkerBoy : 왼쪽 조인은 왼쪽의 행 포함에 영향을 미치지 않으면 서 오른쪽의 행이 존재하지 않도록합니다. 내부 조인은 왼쪽과 오른쪽에 행이 있어야합니다. 내가 여기서하고있는 것은 기본적으로 내부 조인의 역 선택을 얻기 위해 몇 가지 논리를 적용하는 것입니다.
Kris

2
omg 이것은 매우 쉽게 시각화하는 데 도움이되었고 다른 사람들은 5 가지 방법으로 넣었지만 도움이되었습니다. 간단합니다 : 먼저 왼쪽 조인, A의 모든 것, A와 일치하는 B의 모든 것을 얻습니다. 그러나 조인하지 않는 왼쪽 조인 필드에서 발생하는 것처럼 null입니다. 그렇다면 당신은 알 수 있습니다. 이런 식으로 당신은 이제 B에서 일치하지 않은 A의 모든 행을 가지고 있습니다.
Muhammad Umer

7
이 솔루션 (수락 및 투표)만이 유일하다고 생각합니다. 하나 이상의 필드가 등장하는 시나리오에 대해 편집 할 수 있다고 생각합니다. 구체적으로, 필드 광고 field2의 조합이 두 번째 테이블에없는 테이블 1에서 필드 2, 필드 3을 반환합니다. (가)이 답변에 참여 수정하는 것보다 다른, 나는 아래 주장은 다른 "보다 효율적으로 답변"의 일부와 함께 할 수있는 방법이 표시되지 않습니다
TMWP

1
"and"가 올바른 결과를 제공하지 않으므로 "AND t2.name IS NULL"이 아닌 "WHERE t2.name IS NULL"을 사용해야합니다. 나는 왜 그런지 이해하지 못하지만 사실입니다. 테스트했습니다.
user890332

236

당신은 할 수 있습니다

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

또는

SELECT name 
FROM table2 
WHERE NOT EXISTS 
    (SELECT * 
     FROM table1 
     WHERE table1.name = table2.name)

이것을 달성 하기 위해 3 가지 기술에 대한 이 질문 을 참조하십시오


38
많은 양의 데이터를 사용하면 엄청나게 느립니다.
전구 1 1

예, 실제로 매우 느립니다
sirus

존재하지 않는 쿼리의 하위 쿼리에서 "from table1"이 아니어야합니다.
Hound

이것이 얼마나 많은 공감대를 얻었는지에 대해 매우 혼란스러워했습니다. 거의 동일한 수의 키 입력 으로이 문제에 대한 접근 방식이 엄청나게 빠를 때 이것을 사용하는 이유를 생각하기가 매우 어렵습니다.
searchengine27

이것은 나를 위해 일했다 .. 감사합니다
Thameem

81

두 번째 답변에 투표 할 충분한 담당자 점수가 없습니다. 그러나 나는 최고 답변에 대한 의견에 동의하지 않아야합니다. 두 번째 답변 :

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

실제로 FAR이 더 효율적입니다. 왜 그런지 모르겠지만 800k + 이상의 레코드에 대해 실행 중이며 위에 게시 된 두 번째 답변의 이점으로 인해 그 차이가 엄청납니다. 그냥 내 $ 0.02


30
NOT IN 쿼리에서 하위 쿼리는 한 번만 수행됩니다. EXISTS 쿼리에서 하위 쿼리는 모든 행에 대해 수행됩니다
Carrick

1
당신은 굉장합니다 :) 이런 식으로 왼쪽 조인을 사용하여 25 초 쿼리를 0.1 초로 변환합니다.
Bassem Shahin

3
대답은 특정한 순서가 아니므로 두 번째 대답 은 생각한 것을 의미하지 않습니다.

38

이것은 minus조작으로 달성 할 수있는 순수한 이론입니다 .

select id, name from table1
minus
select id, name from table2

이것이 왼쪽 조인보다 훨씬 효율적이라고 생각하십니까?
UHS

그것은해야한다. 빼기 명령은이 정확한 상황을 위해 설계되었습니다. 물론 특정 데이터 세트를 판단하는 유일한 방법은 두 가지 방법 모두를 시도하고 어느 것이 더 빨리 실행되는지 확인하는 것입니다.
Winter

9
T-SQL에서 집합 연산자는 "제외"입니다. 이것은 나에게 매우 편리하며 속도 저하를 일으키지 않았습니다.

2
SQLite에서 "빼기"연산자도 "제외"입니다.
lifjoy

MySQL은 마이너스 연산자를 지원하지 않습니다.
무하마드 아짐


16

함정에주의하십시오. 필드 NameTable1Null이 포함되어 있으면 놀라게됩니다. 더 낫습니다 :

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT ISNULL(name ,'')
     FROM table1)

1
COALESCE> ISNULL (ISNULL은 COALESCE보다 새롭거나 더 나은 언어에 쓸모없는 T-SQL 추가 기능)
Kris

14

다음은 나에게 가장 효과적인 방법입니다.

SELECT *
FROM @T1
EXCEPT
SELECT a.*
FROM @T1 a
JOIN @T2 b ON a.ID = b.ID

이것은 내가 시도한 다른 방법보다 두 배 이상 빠릅니다.


고마워, 이것은 많은 양의 데이터에서도 잘 작동합니다! 그러나 나는 '제외'용어에 대해 궁금합니다.
PatsonLeaner


7

나를 위해 날카롭게 작동

SELECT * 
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL

1

쿼리를 참조하십시오 :

SELECT * FROM Table1 WHERE
id NOT IN (SELECT 
        e.id
    FROM
        Table1 e
            INNER JOIN
        Table2 s ON e.id = s.id);

개념적으로는 : 하위 쿼리에서 일치하는 레코드를 가져온 다음 기본 쿼리에서 하위 쿼리에없는 레코드를 가져옵니다.


0

나는 정답으로 다시 게시 할 것입니다 (나는 아직 시원하지 않기 때문에) .... 다른 사람이 더 나은 설명이 필요하다고 생각하는 경우.

SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL

그리고 FROM에서 mySQL의 테이블 이름 사이에 쉼표가 필요한 구문을 보았지만 sqlLite에서는 공백을 선호하는 것 같습니다.

결론은 잘못된 변수 이름을 사용할 때 질문을 남깁니다. 내 변수가 더 합리적이어야합니다. 그리고 누군가 우리에게 쉼표가 필요하거나 쉼표가 필요없는 이유를 설명해야합니다.


0

특정 사용자를 선택하려면

SELECT tent_nmr FROM Statio_Tentative_Mstr
WHERE tent_npk = '90009'
AND
tent_nmr NOT IN (SELECT permintaan_tent FROM Statio_Permintaan_Mstr)

tent_npk사용자의 기본 키

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