我有两个postgresql表:
table name column names
----------- ------------------------
login_log ip | etc.
ip_location ip | location | hostname | etc.
我想从login_log中获得每个IP地址,它在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)
错误:在“SELECT”处或附近有语法错误
第3行:WHERE NOT EXIST (SELECT ip_location.ip)
我还想知道这个查询(通过调整使其工作)是否是为此目的执行最好的查询。
这个任务基本上有4种技术,都是标准SQL。
不存在
通常在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
);
还要考虑:
EXISTS子查询中哪些内容更容易阅读?
左连接/为空
有时这是最快的。通常最短。通常会产生与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;
除了
短。不容易集成在更复杂的查询中。
SELECT ip
FROM login_log
EXCEPT ALL -- "ALL" keeps duplicates and makes it faster
SELECT ip
FROM ip_location;
注意(每个文档):
除非使用EXCEPT ALL,否则重复项将被消除。
通常,您需要ALL关键字。如果您不介意,仍然使用它,因为它使查询更快。
不是在
只有好的没有NULL值或如果你知道正确处理NULL。我不会把它用于这个目的。而且,表越大,性能就越差。
SELECT ip
FROM login_log
WHERE ip NOT IN (
SELECT DISTINCT ip -- DISTINCT is optional
FROM ip_location
);
NOT IN带有一个“陷阱”,用于捕获两边的NULL值:
查找join不存在的记录
dba也有类似的问题。针对MySQL的SE:
选择第二列的值不在第一列中的行