Seleccionar filas que no están presentes en otra tabla

173

Tengo dos tablas postgresql:

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

Quiero obtener todas las direcciones IP desde las login_logque no haya una fila ip_location.
Intenté esta consulta pero arroja un error de sintaxis.

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`

También me pregunto si esta consulta (con ajustes para que funcione) es la mejor consulta para este propósito.

stUrb
fuente

Respuestas:

387

Existen básicamente 4 técnicas para esta tarea, todas ellas SQL estándar.

NOT EXISTS

A menudo más rápido en 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
   );

Considere también:

LEFT JOIN / IS NULL

A veces esto es más rápido. A menudo más corto. A menudo da como resultado el mismo plan de consulta que 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

Corto. No se integra tan fácilmente en consultas más complejas.

SELECT ip 
FROM   login_log

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

Tenga en cuenta que ( según la documentación ):

los duplicados se eliminan a menos que EXCEPT ALLse use.

Por lo general, querrás la ALLpalabra clave. Si no le importa, aún utilícelo porque hace que la consulta sea más rápida .

NOT IN

Solo bueno sin NULLvalores o si sabe manejarlo NULLadecuadamente. Yo no utilizarlo para este propósito. Además, el rendimiento puede deteriorarse con tablas más grandes.

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

NOT INlleva una "trampa" para los NULLvalores en ambos lados:

Pregunta similar sobre dba.SE dirigida a MySQL:

Erwin Brandstetter
fuente
2
Qué SQL se ejecutaría más rápido teniendo en cuenta que los volúmenes de datos son altos en ambas tablas. (asumiendo en miles de millones)
Teja
EXCEPTO TODO fue más rápido para mí
Dan Parker, el
Tenga cuidado con LEFT JOIN: si hay varias filas coincidentes en la tabla de búsqueda, esto creará una entrada duplicada en su consulta principal para cada fila coincidente, lo que puede no ser deseado.
Matthias Fripp
@MatthiasFripp: Excepto que esto nunca puede ocurrir WHERE i.ip IS NULL, lo que significa que no hay coincidencia en absoluto.
Erwin Brandstetter
@ erwin-brandstetter: Buen punto. Me tropecé pensando en la posibilidad de múltiples coincidencias positivas, pero, por supuesto, todas quedarían excluidas.
Matthias Fripp
2

A.) El comando NO EXISTE, te falta la 'S'.

B.) Use NOT IN en su lugar

SELECT ip 
  FROM login_log 
  WHERE ip NOT IN (
    SELECT ip
    FROM ip_location
  )
;
caleb.breckon
fuente
44
NO IN en grandes conjuntos de datos es una idea terrible. Muy, muy lento. Es malo y debe evitarse.
Grzegorz Grabek
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 ;

Aquí la tabla testcases1 contiene todos los datos y la tabla ejecuciones1 contiene algunos datos entre la tabla testcases1. Estoy recuperando solo los datos que no están presentes en la tabla exections1. (e incluso estoy dando algunas condiciones dentro de las que también puede dar). Especifique la condición que no debería estar allí en la recuperación de datos debe estar entre paréntesis.

Deepak N
fuente
0

esto también se puede probar ...

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
Ahnaf
fuente
2
WHERE ip_location.ip is null- ¿Cómo puede WHEREser cierta la condición? Además, la subconsulta no está correlacionada.
Istiaque Ahmed