SQL-한 테이블에서 다른 테이블에 존재하지 않는 레코드 찾기


310

다음 두 가지 SQL 테이블이 있습니다 (MySQL에서).

Phone_book
+----+------+--------------+
| id | name | phone_number |
+----+------+--------------+
| 1  | John | 111111111111 |
+----+------+--------------+
| 2  | Jane | 222222222222 |
+----+------+--------------+

Call
+----+------+--------------+
| id | date | phone_number |
+----+------+--------------+
| 1  | 0945 | 111111111111 |
+----+------+--------------+
| 2  | 0950 | 222222222222 |
+----+------+--------------+
| 3  | 1045 | 333333333333 |
+----+------+--------------+

phone_number없는 사람들이 어떤 전화를 걸 었는지 어떻게 알 수 Phone_book있습니까? 원하는 출력은 다음과 같습니다.

Call
+----+------+--------------+
| id | date | phone_number |
+----+------+--------------+
| 3  | 1045 | 333333333333 |
+----+------+--------------+

도움을 주시면 감사하겠습니다.

답변:


439

쿼리 최적화 프로그램의 성능과 두 테이블의 상대 크기에 따라 다양한 효율성으로이를 수행하는 여러 가지 방법이 있습니다.

이것은 가장 짧은 진술이며 전화 번호부가 매우 짧은 경우 가장 빠를 수 있습니다.

SELECT  *
FROM    Call
WHERE   phone_number NOT IN (SELECT phone_number FROM Phone_book)

대안 적으로 ( Alterlife 덕분에 )

SELECT *
FROM   Call
WHERE  NOT EXISTS
  (SELECT *
   FROM   Phone_book
   WHERE  Phone_book.phone_number = Call.phone_number)

또는 (Wopr 덕분에)

SELECT * 
FROM   Call
LEFT OUTER JOIN Phone_Book
  ON (Call.phone_number = Phone_book.phone_number)
  WHERE Phone_book.phone_number IS NULL

(다른 사람들이 말했듯이 일반적으로 ' *'가 아닌 원하는 열만 선택하는 것이 가장 좋습니다 )


1
IN을 피하고, EXISTS를 사용하십시오-힌트는 질문 제목에 있습니다
annakata

28
왼쪽 외부 조인은 일반적으로 하위 쿼리의 반복 실행을 방지하므로 가장 빠릅니다.
WOPR

까다 롭지 않지만 내 제안에 대한 하위 쿼리는 <code> select * </ code>가 아닌 <code> select 'x'</ code>를 반환합니다.
Alterlife

yes-MySQL 매뉴얼은 이것이 'EXISTS'쿼리에 대해 정상임을 제안합니다.
Alnitak

2
@Alnitak : 두 번째 쿼리 SELECT *에서는 하위 쿼리 가 필요하지 않습니다 . 대신에 예를 들어 SELECT 1충분할 것입니다.
Alexander Abakumov

90
SELECT Call.ID, Call.date, Call.phone_number 
FROM Call 
LEFT OUTER JOIN Phone_Book 
  ON (Call.phone_number=Phone_book.phone_number) 
  WHERE Phone_book.phone_number IS NULL

쿼리 최적화 프로그램이 마법을 발휘할 수 있도록 하위 쿼리를 제거해야합니다.

또한 누군가가 기본 테이블이나 뷰를 변경하면 비효율적 인 코드를 손상시킬 수 있으므로 "SELECT *"는 사용하지 마십시오.


10
이것은 두 번째 테이블에서 여러 번의 패스를 수행하지 않기 때문에 일반적으로 가장 효율적인 방법입니다.
Nerdfest

3
차라리 사람들이 프로파일하기를 바랍니다. 최고의 SQL 성능 전문가가 아니라면, 가장 빠른 것을 미리 알려주는 것은 매우 어렵습니다 (사용하는 DBMS 엔진에 따라 다름).
bortzmeyer

2
Big O 표기법은이 경우 가장 빠를 것으로 예상되는 것을 쉽게 알려줍니다. 크기가 다릅니다.
Jonesopolis

두 테이블 사이 에 관계 가 있다면 Afterlife의 답변 과 거기에 대한 나의 의견을 참조하십시오 1:N. 또는 추가 기능 DISTINCT으로 볼 Vlado의 대답
ToolmakerSteve

25

아래 코드는 더 큰 데이터 세트를 처리 할 때 위에 제시된 답변보다 약간 더 효율적입니다.

SELECT * FROM Call WHERE 
NOT EXISTS (SELECT 'x' FROM Phone_book where 
Phone_book.phone_number = Call.phone_number)

1
항상 그렇듯이 대상 데이터 세트에 대해 쿼리 성능을 프로파일 링하여 최상의 성능을 가진 데이터 세트를 선택하는 것이 좋습니다. 오늘날 SQL 옵티마이 저는 성능 결과가 놀라 울 정도로 충분합니다.
Greg Hewgill

1
이 방법의 장점 (WORPR의 LEFT OUTER JOIN과 비교)은에 Call일치하는 행이 여러 개인 경우 의 행당 여러 행을 반환하지 않는다는 것 입니다 Phone_book. 즉, 1:N두 테이블간에 관계 가있는 경우 입니다.
ToolmakerSteve

나는 이것으로 시작할 것입니다-그것은 의도를 직접 나타냅니다. 성능이 충분하지 않으면 적절한 색인이 존재하는지 확인하십시오. 그런 다음에, 덜 분명한 것을 시도 LEFT OUTER JOIN하고 성능이 더 좋은지 확인하십시오.
ToolmakerSteve

6
SELECT DISTINCT Call.id 
FROM Call 
LEFT OUTER JOIN Phone_book USING (id) 
WHERE Phone_book.id IS NULL

Phone_book 테이블에서 누락 된 여분의 id를 반환합니다.


4

나는 생각한다

SELECT CALL.* FROM CALL LEFT JOIN Phone_book ON 
CALL.id = Phone_book.id WHERE Phone_book.name IS NULL

id에서 열 call테이블은 같은 값이 아닙니다 id에 열 Phone_book이 값에 가입 할 수 있도록 테이블. 비슷한 접근법에 대해서는 WOPR의 답변을 참조하십시오.
Michael Fredrickson

3
SELECT t1.ColumnID,
CASE 
    WHEN NOT EXISTS( SELECT t2.FieldText  
                     FROM Table t2 
                     WHERE t2.ColumnID = t1.ColumnID) 
    THEN t1.FieldText
    ELSE t2.FieldText
END FieldText       
FROM Table1 t1, Table2 t2

동일한 열에 대해 다른 테이블에 데이터가 없으면 하나의 테이블에서 데이터를 반환합니다.
Harvinder Sidhu

1
SELECT name, phone_number FROM Call a
WHERE a.phone_number NOT IN (SELECT b.phone_number FROM Phone_book b)

이것은 질문에 대한 답변을 제공하지 않습니다. 저자에게 비평을하거나 설명을 요청하려면 게시물 아래에 의견을 남겨주십시오. - 리뷰에서
Dennis Kriechel

@DennisKriechel은 질문에보다 구체적으로 쿼리를 업데이트했습니다.
JoshYates1980

1

또는

select id from call
minus
select id from phone_number

1
(마이너스) 연산자가 새로운 추가 사항이지만 질문에 답이 확실하지 않습니다. 결과적으로 품질이 낮은 대기열에있게되었습니다.이 답변을 향상시킬 수 있습니다.
ste-fu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.