Выберите строки, которых нет в другой таблице


173

У меня есть две таблицы 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`

Мне также интересно, является ли этот запрос (с изменениями, чтобы он работал) наиболее эффективным для этой цели.

Ответы:


387

Есть в основном 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 будет работать быстрее, учитывая, что объемы данных высоки в обеих таблицах. (в миллиардах)
Teja

За исключением того, что ВСЕ было самым быстрым для меня
Дэн Паркер

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

@MatthiasFripp: За исключением того, что это никогда не может произойти WHERE i.ip IS NULL, что означает отсутствие совпадения.
Эрвин Брандштеттер

@ erwin-brandstetter: Хороший вопрос. Я споткнулся, размышляя о возможности нескольких положительных совпадений, но, конечно, все они будут исключены
Матиас Фрипп

2

A.) Команда НЕ СУЩЕСТВУЕТ, вам не хватает буквы «S».

B.) Вместо этого используйте NOT IN

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

4
НЕ в больших наборах данных - ужасная идея. Очень, очень медленно. Это плохо и его следует избегать.
Гжегож Грабек,

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 содержит все данные, а таблица выполнения - содержит некоторые данные из таблицы 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.