web-dev-qa-db-fra.com

SQL - recherche les enregistrements d'une table qui n'existent pas dans une autre

J'ai les deux tables SQL suivantes (dans 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 |
+----+------+--------------+

Comment savoir quels appels ont été passés par des personnes dont phone_number n'est pas dans le Phone_book? La sortie souhaitée serait:

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

Toute aide serait très appréciée.

273
Philip Morton

Il existe différentes façons de procéder, avec une efficacité variable, en fonction de la qualité de votre optimiseur de requêtes et de la taille relative de vos deux tables:

C'est la déclaration la plus courte, et peut être la plus rapide si votre répertoire est très court:

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

alternativement (grâce à Alterlife )

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

ou (grâce à WOPR)

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

(en ignorant que, comme d'autres l'ont déjà dit, il est généralement préférable de sélectionner uniquement les colonnes souhaitées, et non '*')

386
Alnitak
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

Devrait supprimer la sous-requête, ce qui permettrait à l’optimiseur de requêtes d’exploiter sa magie.

Aussi, évitez "SELECT *" car cela peut casser votre code si quelqu'un altère les tables ou les vues sous-jacentes (et que cela est inefficace).

80
WOPR

Le code ci-dessous serait un peu plus efficace que les réponses présentées ci-dessus lorsqu'il s'agit de jeux de données plus volumineux.

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

Cela renverra les identifiants supplémentaires manquants dans votre table Phone_book.

5
Vlado

Je pense

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

Alternativement

select id from call
minus
select id from phone_number
1
elfekz