Wybierz wiersze, których nie ma w innej tabeli

172

Mam dwie tabele postgresql:

table name     column names
-----------    ------------------------
login_log      ip | etc.
ip_location    ip | location | hostname | etc.

Chcę uzyskać każdy adres IP, z login_logktórego nie ma wiersza ip_location.
Próbowałem tego zapytania, ale zgłasza błąd składni.

SELECT login_log.ip 
FROM login_log 
WHERE NOT EXIST (SELECT ip_location.ip
                 FROM ip_location
                 WHERE login_log.ip = ip_location.ip)
ERROR: syntax error at or near "SELECT"
LINE 3: WHERE NOT EXIST (SELECT ip_location.ip`

Zastanawiam się również, czy to zapytanie (z dostosowaniami, aby działało) jest najlepiej działającym zapytaniem do tego celu.

stUrb
źródło

Odpowiedzi:

386

Istnieją zasadniczo 4 techniki tego zadania, wszystkie w standardowym języku SQL.

NOT EXISTS

Często najszybszy w Postgres.

SELECT ip 
FROM   login_log l 
WHERE  NOT EXISTS (
   SELECT  -- SELECT list mostly irrelevant; can just be empty in Postgres
   FROM   ip_location
   WHERE  ip = l.ip
   );

Weź również pod uwagę:

LEFT JOIN / IS NULL

Czasami jest to najszybsze. Często najkrótszy. Często skutkuje tym samym planem zapytań co NOT EXISTS.

SELECT l.ip 
FROM   login_log l 
LEFT   JOIN ip_location i USING (ip)  -- short for: ON i.ip = l.ip
WHERE  i.ip IS NULL;

EXCEPT

Krótki. Nie tak łatwo zintegrować się z bardziej złożonymi zapytaniami.

SELECT ip 
FROM   login_log

EXCEPT ALL  -- "ALL" keeps duplicates and makes it faster
SELECT ip
FROM   ip_location;

Zwróć uwagę, że ( zgodnie z dokumentacją ):

duplikaty są eliminowane, chyba że EXCEPT ALLzostaną użyte.

Zazwyczaj będziesz potrzebować ALLsłowa kluczowego. Jeśli nie zależy ci na tym, nadal używaj go, ponieważ przyspiesza zapytanie .

NOT IN

Tylko dobre bez NULLwartości lub jeśli wiesz, jak NULLprawidłowo obsługiwać . I byłoby nie wykorzystać do tego celu. Ponadto wydajność może się pogorszyć przy większych stołach.

SELECT ip 
FROM   login_log
WHERE  ip NOT IN (
   SELECT DISTINCT ip  -- DISTINCT is optional
   FROM   ip_location
   );

NOT INzawiera „pułapkę” na NULLwartości po obu stronach:

Podobne pytanie na dba.SE skierowane do MySQL:

Erwin Brandstetter
źródło
2
Który SQL działałby szybciej, biorąc pod uwagę duże ilości danych w obu tabelach. (zakładając w miliardach)
Teja
EXCEPT ALL był dla mnie najszybszy
Dan Parker
Uważaj LEFT JOIN- jeśli w tabeli przeglądowej znajduje się wiele pasujących wierszy, spowoduje to utworzenie zduplikowanego wpisu w głównym zapytaniu dla każdego pasującego wiersza, co może nie być pożądane.
Matthias Fripp
@MatthiasFripp: Z wyjątkiem tego, że nigdy nie może się to zdarzyć z WHERE i.ip IS NULL, co oznacza brak dopasowania.
Erwin Brandstetter
@ erwin-brandstetter: Słuszna uwaga. Podskoczyłem myśląc o możliwości wielokrotnych pozytywnych dopasowań, ale oczywiście wszystkie one byłyby wykluczone.
Matthias Fripp
2

A.) Polecenie NIE ISTNIEJE, brakuje litery „S”.

B.) Zamiast tego użyj NOT IN

SELECT ip 
  FROM login_log 
  WHERE ip NOT IN (
    SELECT ip
    FROM ip_location
  )
;
caleb.breckon
źródło
4
NOT IN w przypadku dużych zbiorów danych to okropny pomysł. Bardzo, bardzo wolno. To jest złe i należy go unikać.
Grzegorz Grabek
0

SELECT * FROM testcases1 t WHERE NOT EXISTS ( SELECT 1
FROM executions1 i WHERE t.tc_id = i.tc_id and t.pro_id=i.pro_id and pro_id=7 and version_id=5 ) and pro_id=7 ;

Tutaj tabela testcases1 zawiera wszystkie dane, a tabela wykonań1 zawiera niektóre dane z tabeli testcases1. Pobieram tylko dane, których nie ma w tabeli exections1. (a nawet podam pewne warunki w środku, które również możesz podać.) Określ warunek, którego nie ma podczas pobierania danych, powinien być umieszczony w nawiasach.

Deepak N
źródło
0

to też można spróbować ...

SELECT l.ip, tbl2.ip as ip2, tbl2.hostname
FROM   login_log l 
LEFT   JOIN (SELECT ip_location.ip, ip_location.hostname
             FROM ip_location
             WHERE ip_location.ip is null)tbl2
Ahnaf
źródło
2
WHERE ip_location.ip is null- jak WHEREwarunek może być kiedykolwiek prawdziwy? Ponadto zapytanie podrzędne nie jest skorelowane.
Istiaque Ahmed