다른 테이블에없는 ID로 레코드를 찾기위한 SQL 쿼리


123

데이터베이스에 기본 키를 바인딩하는 두 개의 테이블이 있으며 그 사이에 분리 된 집합을 찾고 싶습니다. 예를 들면

  • Table1열 ( ID, Name)과 샘플 데이터가 있습니다.(1 ,John), (2, Peter), (3, Mary)
  • Table2열 ( ID, Address)과 샘플 데이터가 있습니다.(1, address2), (2, address2)

에서 내가 ID로 행을 가져올 수 있도록 그래서 SQL 쿼리를 작성하는 방법 table1즉 아닙니다 table2. 이 경우 (3, Mary)반품해야합니까?

추신. ID는이 두 테이블의 기본 키입니다.

미리 감사드립니다.


3
향후 질문에 대한 팁 : 항상 사용중인 데이터베이스 시스템 (및 해당 데이터베이스의 버전)을 정의하십시오. SQL 은 대부분의 데이터베이스 시스템에서 사용 하는 구조적 쿼리 언어 일뿐입니다. 실제로는 별 도움이되지 않습니다 ... 종종 데이터베이스에는 문제를 쉽게 해결할 수있는 ANSI / ISO SQL 표준 이상의 확장과 기능이 있습니다. 필요하면 사용중인 데이터베이스 우리에게 얘기를
marc_s

5
@marc_s : 여러 기본 데이터베이스 시스템을 지원해야하거나 데이터베이스 구현이 추상화되어 언어에 구애받지 않는 솔루션을 찾고 있다면 어떨까요?
dwanderson 2014-06-02

안녕하세요 @marc_s, 저는이 경우 PostgreSQL을 사용하고 있습니다. 상기시켜 주셔서 감사합니다.
johnklee

답변:


213

이 시도

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)

8
@PrinceJea 실제로 그것은 다릅니다. 설명 여기를 참조하십시오
오우삼에게

20 개의 데이터가 있으면 작동하지만 20000 개의 데이터가 있으면 작동하지 않습니다. 지금은 혼란 스럽습니다.
Frank

1
이유는 모르겠지만 작동하지 않습니다. 테이블에 약 10000 행이 있습니다. 제 경우에는 @JohnWoo의 솔루션이 잘 작동했습니다.
Munam 유세

4
이 방법은 제한된 수의 값을 가지고 있기 때문에 "Not In"에 너무 많은 값이 있으면 작동하지 않습니다. cf : dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato

2
내가 NOT IN (표 2에서 나는를 선택 WHERE 표에서 난을 선택 :이처럼해야 할 일을했을 내가 null이 아닌 경우 ) 그리고 난 null이 아닌
jaksco

93

사용하다 LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL

이것이 매우 큰 데이터베이스에 대한 더 빠른 접근 방식이라고 생각합니다
Alex Jolig

12

기본적으로 not exists, not inleft join / is null.

IS NULL을 사용한 LEFT JOIN

SELECT  l.*
FROM    t_left l
LEFT JOIN
        t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

SELECT  l.*
FROM    t_left l
WHERE   l.value NOT IN
        (
        SELECT  value
        FROM    t_right r
        )

존재하지 않음

SELECT  l.*
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    t_right r
        WHERE   r.value = l.value
        )

어느 것이 더 낫습니까? 이 질문에 대한 대답은 주요 특정 RDBMS 공급 업체로 분류하는 것이 더 나을 수 있습니다. 일반적으로 select ... where ... in (select...)하위 쿼리의 레코드 수 크기를 알 수없는 경우 사용을 피해야 합니다. 일부 공급 업체는 크기를 제한 할 수 있습니다. 예를 들어 Oracle의 제한은 1,000 입니다. 가장 좋은 방법은 세 가지를 모두 시도하고 실행 계획을 보여주는 것입니다.

구체적의 PostgreSQL의 실행 계획을 형성 NOT EXISTSLEFT JOIN / IS NULL동일하다. 나는 개인적으로 NOT EXISTS더 나은 의도를 보여주기 때문에 옵션을 선호합니다 . 결국 의미론은 A에서 pk B에 존재하지 않는 레코드를 찾으려는 것입니다 .

오래되었지만 여전히 금색이며 PostgreSQL에만 해당됩니다. https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/


10

빠른 대안

각각 ~ 2M 행이있는 두 개의 테이블을 사용하여 몇 가지 테스트 (postgres 9.5에서)를 실행했습니다. 아래의이 쿼리는 제안 된 다른 쿼리보다 최소 5 * 더 나은 성능을 보였습니다.

-- Count
SELECT count(*) FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2;

-- Get full row
SELECT table1.* FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2 JOIN table1 ON t1_not_in_t2.id=table1.id;

1
이것은 @Jhon Woo의 솔루션보다 빠르지 않았습니다. Postgres 9.6을 사용하고 있으며 Jhon의 솔루션 런타임은 약 60ms입니다. 120 초 후에이 솔루션을 사용하고 결과가 없습니다.
froy001

5

위의 @John Woo의 댓글 / 링크에있는 요점을 염두에두면 일반적으로 다음과 같이 처리합니다.

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)

2
SELECT COUNT(ID) FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For count


SELECT ID FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For results
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.