MySQL: wybierz wiersze z tabeli, które nie znajdują się w innej

118

Jak zaznaczyć wszystkie wiersze w jednej tabeli, które nie pojawiają się w innej?

Tabela 1:

+-----------+----------+------------+
| FirstName | LastName | BirthDate  |
+-----------+----------+------------+
| Tia       | Carrera  | 1975-09-18 |
| Nikki     | Taylor   | 1972-03-04 |
| Yamila    | Diaz     | 1972-03-04 |
+-----------+----------+------------+

Tabela 2:

+-----------+----------+------------+
| FirstName | LastName | BirthDate  |
+-----------+----------+------------+
| Tia       | Carrera  | 1975-09-18 |
| Nikki     | Taylor   | 1972-03-04 |
+-----------+----------+------------+

Przykładowe dane wyjściowe dla wierszy w tabeli 1, których nie ma w tabeli 2:

+-----------+----------+------------+
| FirstName | LastName | BirthDate  |
+-----------+----------+------------+
| Yamila    | Diaz     | 1972-03-04 |
+-----------+----------+------------+

Może coś takiego powinno działać:

SELECT * FROM Table1 WHERE * NOT IN (SELECT * FROM Table2)
Christopher Rapcewicz
źródło

Odpowiedzi:

96

Jeśli masz 300 kolumn, jak wspomniałeś w innym komentarzu, i chcesz porównać wszystkie kolumny (zakładając, że wszystkie kolumny mają taką samą nazwę), możesz użyć a, NATURAL LEFT JOINaby niejawnie połączyć wszystkie pasujące nazwy kolumn między dwiema tabelami, aby nie musisz ręcznie wpisywać wszystkich warunków łączenia:

SELECT            a.*
FROM              tbl_1 a
NATURAL LEFT JOIN tbl_2 b
WHERE             b.FirstName IS NULL
Zane Bien
źródło
Zauważ, że działa to tylko zgodnie z oczekiwaniami, gdy żadna z kolumn nie ma wartości NULL. W MySQL NULL! = NULL, więc każdy wiersz, który ma wartość NULL, zostanie zwrócony, nawet jeśli w drugiej tabeli znajduje się zduplikowany wiersz.
Kyle Kochis
84
Jeśli masz 300 kolumn, powinieneś przeprojektować bazę danych.
Iharob Al Asimi
hej, to też działa na mnie, dzięki! ale czy to byłby problem, gdyby liczba rzędów wynosiła> 300, tak jak wspomniałeś powyżej?
thekucays
Nadal nie mam wątpliwości co do zapytania btw .. co jeśli zmienię na przykład „gdzie b.FirstName ma wartość null” na „gdzie b.LastName ma wartość null”? co za różnica? Przepraszam, że pytam, nadal jestem nowy w sql: D
thekucays
184

Musisz dokonać podselekcji na podstawie nazwy kolumny, a nie *.

Na przykład, jeśli masz idpole wspólne dla obu tabel, możesz wykonać:

SELECT * FROM Table1 WHERE id NOT IN (SELECT id FROM Table2)

Więcej przykładów można znaleźć w składni podzapytania MySQL .

Stennie
źródło
1
Dziękuję za wyjaśnienie! ale naprawdę nie muszę opierać wyboru wierszy na żadnym polu, ponieważ jestem zainteresowany dowolną odmianą dowolnego pola w wierszu ...
Jeśli jest tylko kilka kolumn do porównania, możesz wykonać złączenie zgodnie z przykładem @ Steve. Jeśli faktycznie prosisz o ogólne porównanie danych w dwóch tabelach z wieloma kolumnami, prawdopodobnie będziesz chciał poszukać narzędzia porównywania MySQL .
Stennie
2
Zwróć uwagę, że zawsze zwróci to pusty zestaw, jeśli kolumna, którą przeglądasz w tabeli 2, zawiera wartości null. Nie stanowi problemu, jeśli robisz to na podstawie klucza podstawowego, ale ma znaczenie dla osób próbujących użyć tego zapytania w innych kontekstach.
Mark Amery,
4
Ale co, jeśli mówimy o dużych zbiorach danych? A tabela 2 zawiera na przykład 100 milionów wierszy?
kończy
Mądra i sprytna odpowiedź. Dzięki kolego
Anjana Silva
44
SELECT *
FROM Table1 AS a
WHERE NOT EXISTS (
  SELECT *
  FROM Table2 AS b 
  WHERE a.FirstName=b.FirstName AND a.LastName=b.Last_Name
)

EXISTS pomoże Ci...

Ruzbeh Irani
źródło
2
Dobra odpowiedź, ekonomiczna w przypadku dużych zestawów danych, dzięki.
ekerner
Silny. Najlepsza odpowiedź dla dużych zbiorów danych
Ian Chadwick
35

Standardowe LEFT JOIN mogłoby rozwiązać problem, a jeśli pola na złączeniu są indeksowane,
powinno również działać szybciej

SELECT *
FROM Table1 as t1 LEFT JOIN Table2 as t2 
ON t1.FirstName = t2.FirstName AND t1.LastName=t2.LastName
WHERE t2.BirthDate Is Null
Steve
źródło
w porządku, myślę, że to musi być to, a przy okazji dlaczego WHERE t2.Birthdate Is Nullzamiast AND t1.Birthdate = t2.Birthdate?
Ponieważ jeśli to dodasz, to każdy wiersz zostanie zwrócony, mówisz, że w wyniku powinny pojawić się tylko wiersze, których nie ma w drugiej tabeli
Steve
1
To świetna odpowiedź, ponieważ nie wymaga zwracania wszystkich wierszy Table2!
dotancohen
Zgadzam się, świetna odpowiedź. Mam stół składający się z wielu osób pomiędzy 4 stołami, umieszczenie AND w złączeniu wewnętrznym z pewnością będzie bardziej ekonomiczne.
DR.
6

Próbować:

SELECT * FROM table1
    LEFT OUTER JOIN table2
    ON table1.FirstName = table2.FirstName and table1.LastName=table2.LastName
    WHERE table2.BirthDate IS NULL
Sachin Pundir
źródło
4

Spróbuj tego prostego zapytania. Działa doskonale.

select * from Table1 where (FirstName,LastName,BirthDate) not in (select * from Table2);
Vijesh
źródło
-3

To zadziałało dla mnie w Oracle:

SELECT a.* 
    FROM tbl1 a 
MINUS 
SELECT b.* 
    FROM tbl2 b;
Giennadij Sorochan
źródło
Pytanie dotyczyło MySQL.
jelder
-6
SELECT a.* FROM 
FROM tbl_1 a
MINUS
SELECT b.* FROM 
FROM tbl_2 b
Ingrid R. Forsale
źródło