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)

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

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 .


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


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

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

4

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

select * from Table1 where (FirstName,LastName,BirthDate) not in (select * from Table2);


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.