Виберіть рядки, яких немає в іншій таблиці


172

У мене дві таблиці postgresql:

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

Я хочу отримати кожну IP-адресу, з login_logякої немає рядка ip_location.
Я спробував цей запит, але він видає синтаксичну помилку.

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`

Мені також цікаво, чи цей запит (з коригуваннями для його роботи) є найкращим запитом для цієї мети.

Відповіді:


386

В основному для цього завдання є 4 методики, всі вони стандартні SQL.

NOT EXISTS

Найчастіше найшвидший у 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
   );

Також врахуйте:

LEFT JOIN / IS NULL

Іноді це найшвидше. Часто найкоротший. Часто призводить до того ж плану запитів, що і 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

Короткий. Не так легко інтегруватись у складніші запити.

SELECT ip 
FROM   login_log

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

Зауважте, що ( за документацією ):

дублікати усуваються, якщо EXCEPT ALLне використовуються.

Як правило, вам потрібне ALLключове слово. Якщо вам все одно, все одно користуйтеся ним, оскільки це робить запит швидшим .

NOT IN

Тільки добре без NULLзначень або якщо ти вмієш NULLправильно поводитися . Я б не використовував це для цієї мети. Крім того, продуктивність може погіршитися при великих таблицях.

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

NOT INнесе "пастку" для NULLзначень з обох сторін:

Аналогічне запитання щодо dba.SE, орієнтованого на MySQL:


2
Який SQL би працював швидше, враховуючи, що в обох таблицях обсяг даних високий. (припускаючи мільярди)
Тея

ВСЕ ВСЕ було найшвидшим для мене
Ден Паркер

Будьте обережні, LEFT JOINякщо у таблиці пошуку є декілька відповідних рядків, це створить повторний запис у вашому головному запиті для кожного відповідного рядка, який може не бути потрібним.
Маттіас Фріпп

@MatthiasFripp: За винятком того, що цього ніколи не може відбутися WHERE i.ip IS NULL, тобто взагалі немає відповідності.
Ервін Брандстеттер

@ erwin-marketetter: Добре. Я спонукав себе думати про можливість декількох позитивних матчів, але, звичайно, все це буде виключено.
Маттіас Фріпп

2

A.) Команда НЕ існує, у вас пропущено 'S'.

B.) Замість цього використовуйте NOT IN

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

4
NOT IN на великих наборах даних - жахлива ідея. Дуже, дуже повільно. Це погано і його слід уникати.
Гжегож Грабек

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 ;

Тут таблиця testcases1 містить усі дані та виконання1 таблиця містить деякі дані серед testcases1 таблиця. Я отримую лише ті дані, яких немає у таблиці exections1. (і навіть я даю деякі умови всередині, які ви також можете надати.) вкажіть умову, якої не повинно бути там, для отримання даних має бути всередині дужок.


0

це також можна спробувати ...

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- як WHEREумова може бути колись справжньою? Також підзапит не є співвіднесеним.
Істіак Ахмед
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.