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


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

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

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.