SQL – encontre registros de uma tabela que não existem em outra

Eu tenho as seguintes duas tabelas SQL (no 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 | +----+------+--------------+ 

Como descubro quais chamadas foram feitas por pessoas cujo número de phone_number não está no Phone_book ? A saída desejada seria:

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

Qualquer ajuda seria muito apreciada.

Há várias maneiras diferentes de fazer isso, com eficiência variável, dependendo de quão bom é o otimizador de consulta e o tamanho relativo de suas duas tabelas:

Esta é a declaração mais curta e pode ser mais rápida se a sua agenda telefônica for muito pequena:

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

alternativamente (graças a Alterlife )

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

ou (graças a WOPR)

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

(ignorando que, como outros já disseram, normalmente é melhor selecionar apenas as colunas que você quer, não ‘ * ‘)

 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 

Deve remover a subconsulta, permitindo que o otimizador de consulta trabalhe sua mágica.

Além disso, evite “SELECT *” porque ele pode quebrar seu código se alguém alterar as tabelas ou visualizações subjacentes (e é ineficiente).

O código abaixo seria um pouco mais eficiente do que as respostas apresentadas acima ao lidar com conjuntos de dados maiores.

 SELECT * FROM Call WHERE NOT EXISTS (SELECT 'x' FROM Phone_book where Phone_book.phone_number = Call.phone_number) 
 SELECT DISTINCT Call.id FROM Call LEFT OUTER JOIN Phone_book USING (id) WHERE Phone_book.id IS NULL 

Isso retornará os IDs extras que estão faltando na sua tabela Phone_book.

eu acho que

 SELECT CALL.* FROM CALL LEFT JOIN Phone_book ON CALL.id = Phone_book.id WHERE Phone_book.name IS NULL 
 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 
 SELECT name, phone_number FROM Call a WHERE a.phone_number NOT IN (SELECT b.phone_number FROM Phone_book b) 

Alternativamente,

 select id from call minus select id from phone_number