Pilih baris yang tidak ada di tabel lain

173

Saya punya dua tabel postgresql:

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

Saya ingin mendapatkan setiap alamat IP login_logyang tidak memiliki baris ip_location.
Saya mencoba kueri ini tetapi ada kesalahan sintaksis.

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`

Saya juga ingin tahu apakah kueri ini (dengan penyesuaian agar berfungsi) adalah kueri yang berkinerja terbaik untuk tujuan ini.

stUrb
sumber

Jawaban:

387

Pada dasarnya ada 4 teknik untuk tugas ini, semuanya SQL standar.

NOT EXISTS

Seringkali tercepat di 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
   );

Pertimbangkan juga:

LEFT JOIN / IS NULL

Terkadang ini yang tercepat. Seringkali terpendek. Seringkali menghasilkan rencana kueri yang sama dengan 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

Pendek. Tidak mudah diintegrasikan dalam permintaan yang lebih kompleks.

SELECT ip 
FROM   login_log

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

Perhatikan bahwa ( per dokumentasi ):

duplikat dihilangkan kecuali EXCEPT ALLdigunakan.

Biasanya, Anda menginginkan ALLkata kunci. Jika Anda tidak peduli, tetap gunakan itu karena membuat kueri lebih cepat .

NOT IN

Hanya bagus tanpa NULLnilai atau jika Anda tahu untuk menangani NULLdengan benar. Saya tidak akan menggunakannya untuk tujuan ini. Juga, kinerja dapat memburuk dengan tabel yang lebih besar.

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

NOT INmembawa "jebakan" untuk NULLnilai di kedua sisi:

Pertanyaan serupa tentang dba.SE yang ditargetkan di MySQL:

Erwin Brandstetter
sumber
2
SQL mana yang akan berjalan lebih cepat mengingat volume data yang tinggi di kedua tabel. (dengan asumsi miliaran)
Teja
KECUALI SEMUA adalah yang tercepat bagi saya
Dan Parker
Hati-hati dengan LEFT JOIN- jika ada beberapa baris yang cocok di tabel pencarian, ini akan membuat entri duplikat dalam permintaan utama Anda untuk setiap baris yang cocok, yang mungkin tidak diinginkan.
Matthias Fripp
@MatthiasFripp: Kecuali hal ini tidak pernah terjadi WHERE i.ip IS NULL, artinya tidak cocok sama sekali.
Erwin Brandstetter
@ erwin-brandstetter: Poin bagus. Saya tersandung berpikir tentang kemungkinan beberapa pertandingan positif, tetapi tentu saja itu semua akan dikecualikan.
Matthias Fripp
2

A.) Perintah BUKAN ADA, Anda kehilangan 'S'.

B.) Gunakan NOT IN sebagai gantinya

SELECT ip 
  FROM login_log 
  WHERE ip NOT IN (
    SELECT ip
    FROM ip_location
  )
;
caleb.breckon
sumber
4
BUKAN DI pada dataset besar adalah ide yang buruk. Sangat, sangat lambat. Itu buruk dan harus dihindari.
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 ;

Di sini tabel testcases1 berisi semua data dan tabel execututions1 berisi beberapa data di antara tabel testcases1. Saya hanya mengambil data yang tidak ada dalam tabel exections1. (dan bahkan saya memberikan beberapa kondisi di dalam yang juga dapat Anda berikan.) tentukan kondisi yang seharusnya tidak ada dalam pengambilan data harus di dalam kurung.

Deepak N
sumber
0

ini juga bisa dicoba ...

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
sumber
2
WHERE ip_location.ip is null- bagaimana WHEREkondisinya menjadi benar? Juga, sub-kueri bukan yang berkorelasi.
Istiaque Ahmed