Jak wybrać wszystkie rekordy z jednej tabeli, które nie istnieją w innej tabeli?

469

tabela1 (identyfikator, nazwa)
tabela2 (identyfikator, nazwa)

Pytanie:

SELECT name   
FROM table2  
-- that are not in table1 already
z-boss
źródło

Odpowiedzi:

843
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL

P : Co się tutaj dzieje?

Odp . : Koncepcyjnie wybieramy wszystkie wiersze table1i dla każdego wiersza próbujemy znaleźć wiersz table2o tej samej wartości dla namekolumny. Jeśli nie ma takiego wiersza, po prostu pozostawiamy table2część naszego wyniku pustą dla tego wiersza. Następnie ograniczamy nasz wybór, wybierając tylko te wiersze w wyniku, w których pasujący wiersz nie istnieje. Na koniec ignorujemy wszystkie pola z naszego wyniku, z wyjątkiem namekolumny (tej, z której jesteśmy pewni, że istnieje table1).

Chociaż może nie być to najbardziej wydajna metoda we wszystkich przypadkach, powinna ona działać w zasadzie w każdym silniku bazy danych, który próbuje zaimplementować ANSI 92 SQL

Kris
źródło
16
@ z-boss: Jest to również najmniej wydajny program SQL Server: wyjaśnieniextended.com
OMG Ponies
7
@BunkerBoy: Łączenie po lewej stronie nie pozwala na istnienie wierszy po prawej, bez wpływu na włączenie wierszy po lewej stronie. Połączenie wewnętrzne wymaga obecności rzędów po lewej i prawej stronie. To, co robię tutaj, to zastosowanie logiki, aby w zasadzie uzyskać odwrotny wybór sprzężenia wewnętrznego.
Kris,
2
omg to pomogło bardzo łatwo wizualizować, inni przedstawili to na 5 różnych sposobów, ale to pomogło. proste: najpierw dostajesz lewe łączenie, wszystko w A i wszystko w B, które pasują do A. Ale jak to się dzieje w lewym łączeniu pola, które się nie łączą, są po prostu puste. Potem mówisz, ok, chcę tylko, żeby były puste. W ten sposób masz teraz wszystkie wiersze w A, które nie miały dopasowania w B
Muhammad Umer
7
Należy zauważyć, że to rozwiązanie (przyjęte i przegłosowane) jest jedynym, moim zdaniem, zredagowanym dla scenariusza, w którym wchodzi więcej niż jedno pole. W szczególności zwracam pole, pole 2, pole 3 z tabeli pierwszej, gdzie kombinacji pola reklamy pola 2 nie ma w drugiej tabeli. Poza modyfikacją złączenia w tej odpowiedzi, nie widzę sposobu, aby to zrobić z niektórymi innymi „bardziej wydajnymi odpowiedziami”, o których
mowa
1
Upewnij się tylko, że używasz „GDZIE t2.nazwa jest zerowa”, a nie „I t2.nazwa jest zerowa”, ponieważ „i” nie da poprawnych wyników. Naprawdę nie rozumiem dlaczego, ale to fakt, przetestowałem to.
user890332,
236

Możesz albo

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

lub

SELECT name 
FROM table2 
WHERE NOT EXISTS 
    (SELECT * 
     FROM table1 
     WHERE table1.name = table2.name)

Zobacz to pytanie, aby uzyskać 3 techniki umożliwiające osiągnięcie tego celu

froadie
źródło
38
Jest to niezwykle wolne w przypadku dużych ilości danych.
Żarówka 1
Tak, rzeczywiście jest bardzo powolny
sirus
Czy nie powinno być „z tabeli 1” w podzapytaniu nieistniejącego zapytania?
Hound
Bardzo zdezorientowany, skąd tyle głosów poparcia. Trudno mi znaleźć powód, aby kiedykolwiek tego używać, gdy istnieje podejście do tego problemu, które jest niesamowicie szybsze z mniej więcej taką samą liczbą naciśnięć klawiszy.
searchengine27
Ten zadziałał dla mnie .. Dziękujemy
Thameem
81

Nie mam wystarczającej liczby punktów do powtórzenia drugiej odpowiedzi. Ale muszę się nie zgodzić z komentarzami do pierwszej odpowiedzi. Druga odpowiedź:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

Czy FAR jest bardziej wydajny w praktyce. Nie wiem dlaczego, ale korzystam z rekordów powyżej 800 tys. I różnica jest ogromna, zważywszy na przewagę nad drugą odpowiedzią zamieszczoną powyżej. Tylko moje 0,02 $

Tan Rezaei
źródło
30
W zapytaniu NOT IN podzapytanie jest wykonywane tylko raz, w zapytaniu EXISTS jest wykonywane podzapytanie dla każdego wiersza
Carrick
1
jesteś niesamowity :) w ten sposób przekonwertowałem moje 25-sekundowe zapytanie za pomocą lewego złącza do zaledwie 0,1 sekundy
Bassem Shahin
3
odpowiedzi nie są w żadnej określonej kolejności, więc druga odpowiedź nie oznacza, co według ciebie znaczyło.
38

Jest to czysta teoria mnogości, którą można osiągnąć za pomocą minusoperacji.

select id, name from table1
minus
select id, name from table2
Zimowy
źródło
Czy uważasz, że jest to o wiele wydajniejsze niż lewe dołączenie?
2014
Powinno być. Polecenie minus jest przeznaczone do tej właśnie sytuacji. Oczywiście jedynym sposobem oceny konkretnego zestawu danych jest wypróbowanie go w obie strony i sprawdzenie, który z nich działa szybciej.
Zima
9
W języku T-SQL operatorem zestawu jest „oprócz”. Jest to dla mnie bardzo wygodne i nie spowodowało żadnego spowolnienia.
2
W SQLite operator „minus” jest również „wyjątkiem”.
dożywotnio
MySQL nie obsługuje operatora MINUS.
Muhammad Azeem
16

Uważaj na pułapki. Jeśli pole Namew Table1zawierać wartości null jesteś w niespodzianki. Lepsze jest:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT ISNULL(name ,'')
     FROM table1)
użytkownik4872693
źródło
1
COALESCE> ISNULL (ISNULL to bezużyteczny dodatek T-SQL do języka, który nie robi nic nowego ani lepszego niż COALESCE)
Kris
14

Oto, co działało dla mnie najlepiej.

SELECT *
FROM @T1
EXCEPT
SELECT a.*
FROM @T1 a
JOIN @T2 b ON a.ID = b.ID

Było to ponad dwa razy szybciej niż jakakolwiek inna metoda, którą wypróbowałem.

Kok
źródło
Dzięki, Działa to dobrze również z dużą ilością danych! Ale zastanawiam się tylko nad terminem „z wyjątkiem”.
PatsonLeaner
7

To działa dla mnie ostro

SELECT * 
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL
David Fawzy
źródło
1

Zobacz zapytanie:

SELECT * FROM Table1 WHERE
id NOT IN (SELECT 
        e.id
    FROM
        Table1 e
            INNER JOIN
        Table2 s ON e.id = s.id);

Koncepcyjnie byłoby: Pobranie pasujących rekordów w podzapytaniu, a następnie w głównym zapytaniu pobranie rekordów, które nie znajdują się w podzapytaniu.

Jawahar
źródło
0

Zamierzam ponownie opublikować (ponieważ nie jestem jeszcze wystarczająco fajny, aby skomentować) w prawidłowej odpowiedzi ... na wypadek, gdyby ktokolwiek pomyślał, że trzeba to lepiej wyjaśnić.

SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL

I widziałem składnię w FROM wymagającą przecinków między nazwami tabel w mySQL, ale w sqlLite wydawało się, że wolała miejsce.

Najważniejsze jest to, że kiedy używasz złych nazw zmiennych, pozostawia pytania. Moje zmienne powinny mieć większy sens. I ktoś powinien wyjaśnić, dlaczego potrzebujemy przecinka, czy nie przecinka.

Adrian Roth
źródło
0

Jeśli chcesz wybrać konkretnego użytkownika

SELECT tent_nmr FROM Statio_Tentative_Mstr
WHERE tent_npk = '90009'
AND
tent_nmr NOT IN (SELECT permintaan_tent FROM Statio_Permintaan_Mstr)

Jest tent_npkto klucz podstawowy użytkownika

Fragmantedbin
źródło