Diğer tabloda bulunmayan satırları seçme


173

İki postgresql tablom var:

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

login_logSatırı olmayan her IP adresini almak istiyorum ip_location.
Bu sorguyu denedim ama bir sözdizimi hatası atar.

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`

Ayrıca bu sorguyu (işe yaraması için ayarlamalar ile) bu amaç için en iyi performans gösteren sorgu olup olmadığını merak ediyorum.

Yanıtlar:


387

Bu görev için temel olarak hepsi standart SQL olmak üzere 4 teknik vardır.

NOT EXISTS

Genellikle Postgres'te en hızlı.

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

Ayrıca şunu da dikkate alın:

LEFT JOIN / IS NULL

Bazen bu en hızlısıdır. Genellikle en kısa. Genellikle aynı sorgu planıyla sonuçlanır 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

Kısa. Daha karmaşık sorgulara kolayca entegre edilemez.

SELECT ip 
FROM   login_log

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

Unutmayın ( belgelere göre ):

kullanılmadıkça kopyalar elimine EXCEPT ALLedilir.

Genellikle, ALLanahtar kelimeyi istersiniz . Umursamıyorsanız, sorguyu daha hızlı hale getirdiği için hala kullanın .

NOT IN

Sadece değersiz NULLveya doğru idare ediyorsanız iyi NULL. Ben ediyorum değil bu amaç için kullanıyoruz. Ayrıca, daha büyük tablolarda performans düşebilir.

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

NOT INNULLher iki taraftaki değerler için bir "tuzak" taşır :

MySQL'i hedefleyen dba.SE ile ilgili benzer soru:


2
Her iki tabloda da veri hacimlerinin yüksek olduğu düşünüldüğünde hangi SQL daha hızlı çalışır. (milyarlarca olduğu varsayılarak)
Teja

TÜM hariç, benim için en hızlı
Dan Parker

Dikkatli olun LEFT JOIN- arama tablosunda birden fazla eşleşen satır varsa, bu, her eşleşen satır için ana sorgunuzda istenmeyebilecek yinelenen bir giriş oluşturur.
Matthias Fripp

@MatthiasFripp: Bunun hiçbir zaman gerçekleşemeyeceği WHERE i.ip IS NULL, yani hiçbir eşleşme olmadığı anlamına gelir .
Erwin Brandstetter

@ erwin-brandstetter: İyi nokta. Birden fazla pozitif eşleşme olasılığını düşünmeye başladım, ama elbette bunların hepsi hariç tutulacaktı.
Matthias Fripp

2

A.) Komut VAR DEĞİL, 'S' eksik.

B.) Bunun yerine NOT IN kullanın

SELECT ip 
  FROM login_log 
  WHERE ip NOT IN (
    SELECT ip
    FROM ip_location
  )
;

4
Büyük veri kümelerinde NOT korkunç bir fikirdir. Çok, çok yavaş. Kötü ve kaçınılmalıdır.
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 ;

Burada testcases1 tablosu tüm verileri ve yürütmeler1 tablosu testcas11 tablosu arasında bazı veriler içerir. Yalnızca exections1 tablosunda bulunmayan verileri alıyorum. (ve hatta ben de verebileceğiniz bazı koşullar veriyorum.) veri almada olmaması gereken koşulu parantez içinde olmalıdır.


0

bu da denenebilir ...

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- durum nasıl WHEREdoğru olabilir? Ayrıca, alt sorgu ilişkili bir sorgu değildir.
Istiaque Ahmed
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.