Выберите строки, которых нет в другой таблице
У меня есть две таблицы 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`
Мне также интересно, является ли этот запрос (с изменениями, чтобы он работал) наиболее эффективным для этой цели.
4 ответа
Есть в основном 4 метода для этой задачи, все они стандартные SQL.
NOT EXISTS
Часто самый быстрый в Postgres.
SELECT ip
FROM login_log l
WHERE NOT EXISTS (
SELECT -- mostly irrelevant what's here; might just be empty in pg
FROM ip_location
WHERE ip = l.ip
);
Также учтите:
LEFT JOIN / IS NULL
Иногда это быстрее всего. Часто самый короткий.
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, to keep duplicate rows and make 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:
A.) Команда НЕ СУЩЕСТВУЕТ, вам не хватает "S".
B.) Вместо этого используйте NOT IN
SELECT ip
FROM login_log
WHERE ip NOT IN (
SELECT ip
FROM ip_location
)
;
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. (и даже я даю некоторые условия внутри, которые вы также можете указать.) Укажите условие, которого не должно быть при извлечении данных, должно быть в скобках.
Это тоже можно попробовать...
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