Zapytanie SQL w celu znalezienia rekordu o identyfikatorze, którego nie ma w innej tabeli

123

Mam dwie tabele z powiązanym kluczem podstawowym w bazie danych i chcę znaleźć rozłączny zestaw między nimi. Na przykład,

  • Table1zawiera kolumny ( ID, Name) i przykładowe dane:(1 ,John), (2, Peter), (3, Mary)
  • Table2zawiera kolumny ( ID, Address) i przykładowe dane:(1, address2), (2, address2)

Jak więc utworzyć zapytanie SQL, aby pobrać wiersz z identyfikatorem, table1którego nie ma w table2. W takim razie (3, Mary)należy zwrócić?

Ps. Identyfikator jest kluczem podstawowym dla tych dwóch tabel.

Z góry dziękuję.

johnklee
źródło
3
Wskazówka na przyszłe pytania: zawsze określaj, jakiego systemu baz danych (i której wersji) używasz. SQL to po prostu Structured Query Language używany w większości systemów baz danych - to niewiele pomaga ... często bazy danych mają rozszerzenia i funkcje znacznie wykraczające poza standard ANSI / ISO SQL, które ułatwiają rozwiązanie problemu - ale w tym celu musisz nam powiedzieć, jakiej bazy danych używasz
marc_s
5
@marc_s: A co, jeśli szukają rozwiązania niezależnego od języka, ponieważ muszą obsługiwać wiele bazowych systemów baz danych lub implementacja bazy danych jest oderwana?
dwanderson
Cześć @marc_s, w tym przypadku używam PostgreSQL. Dzięki za przypomnienie.
johnklee

Odpowiedzi:

213

Spróbuj tego

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)
Książę Jea
źródło
8
@PrinceJea właściwie to zależy. Zobacz tutaj po wyjaśnienie
John Woo,
Kiedy mam 20 danych, to działa, ale kiedy mam 20000 danych, to nie działa, jestem teraz zdezorientowany.
Frank
1
Nie mam pojęcia, dlaczego, ale to nie działa. Mam około 10000 wierszy w tabeli. W moim przypadku rozwiązanie @JohnWoo działało dobrze.
Munam Yousuf
4
To nie zadziała przy zbyt wielu wartościach w „Not In”, ponieważ ta metoda ma ograniczoną liczbę wartości. Cf
G.Busato,
2
Musiałem to zrobić w ten sposób: wybierz i z tabeli 1 GDZIE NIE WCHODZĘ (SELECT i FROM Table2, gdzie i nie jest null ) i nie jest null
jaksco
93

Posługiwać się LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL
John Woo
źródło
Myślę, że jest to szybsze podejście w przypadku bardzo dużej bazy danych
Alex Jolig
13

Istnieją 3 sposoby na to: not exists, not ini left join / is null.

LEFT JOIN z IS NULL

SELECT  l.*
FROM    t_left l
LEFT JOIN
        t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

NIE W

SELECT  l.*
FROM    t_left l
WHERE   l.value NOT IN
        (
        SELECT  value
        FROM    t_right r
        )

NIE ISTNIEJE

SELECT  l.*
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    t_right r
        WHERE   r.value = l.value
        )

Który jest lepszy? Odpowiedź na to pytanie mogłaby być lepsza, gdyby została podzielona na głównych, konkretnych dostawców RDBMS. Ogólnie rzecz biorąc, należy unikać stosowania, select ... where ... in (select...)gdy wielkość liczby rekordów w zapytaniu podrzędnym jest nieznana. Niektórzy dostawcy mogą ograniczać rozmiar. Na przykład Oracle ma limit 1000 . Najlepiej jest wypróbować wszystkie trzy i pokazać plan wykonania.

W szczególności z PostgreSQL, plan wykonania NOT EXISTSi LEFT JOIN / IS NULLsą takie same. Osobiście wolę tę NOT EXISTSopcję, ponieważ lepiej pokazuje zamiar. Po tym wszystkim jest to, że semantyczna chcesz znaleźć rekordy w pk że nie istnieją w B .

Stary, ale wciąż złoty, specyficzny dla PostgreSQL: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/

L. Holanda
źródło
10

Szybka alternatywa

Przeprowadziłem kilka testów (na postgres 9.5) używając dwóch tabel z ~ 2M wierszami każda. Poniższe zapytanie było co najmniej 5 * lepsze niż pozostałe proponowane zapytania:

-- Count
SELECT count(*) FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2;

-- Get full row
SELECT table1.* FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2 JOIN table1 ON t1_not_in_t2.id=table1.id;
polvoazul
źródło
1
Nie było to szybsze niż rozwiązanie @Jhon Woo. Używam Postgres 9.6, a czas działania rozwiązania Jhon wynosi około 60 ms. Aż u mnie to rozwiązanie po 120 sekundach i bez rezultatu.
froy001
5

Mając na uwadze uwagi przedstawione w komentarzu / linku @John Woo powyżej, zazwyczaj radziłbym sobie z tym w następujący sposób:

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)
CaseyR
źródło
2
SELECT COUNT(ID) FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For count


SELECT ID FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For results
JoshYates1980
źródło