选择其他表中不存在的行

时间:2013-10-14 15:15:30

标签: sql postgresql null left-join exists

我有两个postgresql表:

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

我想从login_log获取ip_location中没有行的每个IP地址。
我尝试了这个查询,但它会引发语法错误。

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 个答案:

答案 0 :(得分:301)

这项任务基本上有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;

请注意(per documentation):

  

除非使用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带有“{1}}值的”陷阱“:

针对MySQL的dba.SE上的类似问题:

答案 1 :(得分:3)

A。)命令不是EXISTS,你错过了'S'。

B。)改为使用NOT IN

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

答案 2 :(得分: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

答案 3 :(得分: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表中不存在的数据。 (甚至我给出了一些你也可以给出的条件。)指定条件,不应该在那里检索数据应该在括号内。