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.

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:


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
  )
;

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.


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

2
WHERE ip_location.ip is null- jak WHEREwarunek może być kiedykolwiek prawdziwy? Ponadto zapytanie podrzędne nie jest skorelowane.
Istiaque Ahmed
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.