2008-09-29 14 views
23

Tengo dos tablas que están unidas.¿Cómo encuentro registros que no están unidos?

A tiene muchos B

Normalmente puede hacer:

select * from a,b where b.a_id = a.id 

para obtener todos los registros de una que tiene un registro en b.

¿Cómo obtengo solo los registros en un archivo que no tiene nada en b?

Respuesta

42
select * from a where id not in (select a_id from b) 

O como algunas otras personas sobre este tema dice:

select a.* from a 
left outer join b on a.id = b.a_id 
where b.a_id is null 
2

seleccionar * de un id donde no en (seleccione A_ID de b)

+1

Esto será extremadamente costoso ya que el motor tiene que generar la subconsulta en su totalidad antes de que pueda comenzar a eliminar las tuplas de a. No es una buena idea en general. – dland

10
select * from a 
left outer join b on a.id = b.a_id 
where b.a_id is null 
+0

creo que esto externa izquierda llevará a cabo mucho mejor que la cláusula 'en', a menos que el optimizador de consultas de los trata de la misma ... – Codewerks

+0

Es más o menos lo hace. Echale un vistazo. –

+0

Sí, curiosamente, el plan de consulta tiene un strep adicional (Filtro) para la combinación izquierda y el 'donde está' se resuelve a una 'unión anti semi derecha' ... lo que sea que ... – Codewerks

5

Otro enfoque:

select * from a where not exists (select * from b where b.a_id = a.id) 

El enfoque "existe" es útil si th Hay alguna otra cláusula de "dónde" que debe adjuntar a la consulta interna.

1

es probable que obtener un mucho mejor rendimiento (que el uso de 'no') si se utiliza una combinación externa:

select * from a left outer join b on a.id = b.a_id where b.a_id is null; 
0

Otra forma de escribirlo

select a.* from a left outer join b on a.id = b.id where b.id is null

Ay, golpeado por Nathan :)

0

Esto lo protegerá de nulos en la cláusula IN, lo que puede causar un comportamiento inesperado.

seleccionar * de un donde id no en (seleccione [a id] de b donde [a id] no es nulo)

+0

Es mejor que uses una combinación externa izquierda en lugar de usar un predicado IN en primer lugar. – dland

+0

¿Alguna razón para esta opinión? –

3
SELECT id FROM a 
EXCEPT 
SELECT a_id FROM b; 
+0

La palabra clave 'EXCEPT' es' MINUS' en Oracle. – onedaywhen

0

En caso de un join es bastante rápido, pero cuando estamos eliminando registros de la base de datos que tiene aproximadamente 50 millones de registros y 4 y más uniones debido a claves externas, lleva unos minutos hacerlo. mucho más rápido para su uso cuando no está en condiciones de esta manera:

select a.* from a 
where a.id NOT IN(SELECT DISTINCT a_id FROM b where a_id IS NOT NULL) 
//And for more joins 
AND a.id NOT IN(SELECT DISTINCT a_id FROM c where a_id IS NOT NULL) 

también puedo recomendado este enfoque para borrar en caso de que no tenemos configurado en cascada eliminar. Esta consulta toma solo unos segundos.

0

El primer enfoque es

select a.* from a where a.id not in (select b.ida from b) 

el segundo enfoque es

select a.* 
    from a left outer join b on a.id = b.ida 
    where b.ida is null 

El primer enfoque es muy caro. El segundo enfoque es mejor.

Con PostgreSql 9.4, hice la función "explicar consulta" y la primera consulta como un costo de costo = 0.00 ..1982043603.32. En lugar la consulta de combinación como un costo de costo = 45946.77..45946.78

Por ejemplo, puedo buscar todos los productos que no son compatibles con ningún vehículo. Tengo 100k productos y más de 1m de compatibilidades.

select count(*) from product a left outer join compatible c on a.id=c.idprod where c.idprod is null 

La consulta de unión gastó aproximadamente 5 segundos, en cambio, la versión de la subconsulta nunca ha terminado en 3 minutos.

Cuestiones relacionadas