2008-12-15 7 views
226

Tengo las siguientes dos tablas SQL (MySQL):SQL - encontrar los registros de una tabla que no existen en otro

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 | 
+----+------+--------------+ 

¿Cómo me entero de que las llamadas fueron hechas por personas cuyos phone_number no está en el Phone_book? La salida deseada sería:

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

Cualquier ayuda sería muy apreciada.

Respuesta

307

Hay varias maneras diferentes de hacer esto, con eficacia variable, dependiendo de lo bien que su optimizador de consultas es, y el tamaño relativo de sus dos tablas:

Esta es la declaración más corta, y puede ser más rápida si su libreta de teléfonos es muy corto:

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

alternativamente (gracias a Alterlife)

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

o (gracias 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 

(haciendo caso omiso de que, como otros han dicho, la cual es normalmente la mejor manera de seleccionar sólo las columnas que desee, no '*')

+1

Debe evitarse en, USE existe - la pista está en el título de la pregunta – annakata

+16

La combinación externa izquierda es, probablemente, el más rápido en el caso general, ya que impide la ejecución de los repetidos subconsulta. – WOPR

+0

No ser quisquilloso, pero la subconsulta en mi sugerencia devuelve select 'x' y no select * Alterlife

17

El código siguiente podría ser un poco más eficiente que las respuestas presentadas anteriormente cuando se trata de conjuntos de datos más grandes.

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

Como siempre, vale la pena perfilar el rendimiento de las consultas contra su conjunto de datos de destino para elegir el que tenga el mejor rendimiento. Los optimizadores de SQL son lo suficientemente buenos en estos días que los resultados de rendimiento a menudo son sorprendentes. –

59
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 

debe quitar la subconsulta, permitiendo que el optimizador de consultas a trabajar su magia.

Además, evite "SELECT *" porque puede romper su código si alguien altera las tablas o vistas subyacentes (y es ineficaz).

+6

Este es generalmente el método más eficiente ya que no realiza múltiples pases en la segunda tabla ... espero que algunas personas lean los comentarios. – Nerdfest

+2

Prefiero tener ese perfil de personas: a menos que seas un experto en rendimiento de SQL, decir con anticipación cuál será el más rápido es bastante difícil (y depende del motor DBMS que uses). – bortzmeyer

+1

La notación Big O le indicará fácilmente qué puede esperar que sea más rápido en este caso. Son órdenes de magnitud diferentes. – Jonesopolis

4

creo

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

La columna 'id' en la tabla' call' no tiene el mismo valor que la columna 'id' en la tabla' Phone_book', por lo que no puede unirse a estos valores. Ver la respuesta de WOPR para un enfoque similar. –

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

Esto devolverá el extra id-s que faltan en la tabla Phone_book.

1
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 
+0

Esto le devolverá los datos de una tabla si los datos no están presentes en otra tabla para la misma columna –

+0

¿Podría también agregar alguna explicación de lo que esto resuelve? –

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

Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar aclaraciones de un autor, deje un comentario debajo de su publicación. - [De la crítica] (/ reseña/mensajes de baja calidad/10501884) –

+0

@DennisKriechel consulta actualizada para que sea más específica a la pregunta. – JoshYates1980

0

Alternativamente,

select id from call 
minus 
select id from phone_number 
+1

No estoy seguro de que esto responda la pregunta, ya que el operador (aunque MINUS) es una nueva adición. Esto terminó en la cola de baja calidad; es posible que desee mejorar esta respuesta. –

Cuestiones relacionadas