2009-02-03 18 views
11

Estoy intentando escribir una consulta para buscar registros que no tienen un registro coincidente en otra tabla.Buscar registros no coincidentes con SQL

Por ejemplo, tengo un dos tablas cuyas estructuras se ve algo como esto:

 
Table1 
    State | Product | Distributor | other fields 
    CA | P1  | A   | xxxx 
    OR | P1  | A   | xxxx 
    OR | P1  | B   | xxxx 
    OR | P1  | X   | xxxx 
    WA | P1  | X   | xxxx 
    VA | P2  | A   | xxxx 

Table2 
    State | Product | Version | other fields 
    CA | P1  | 1.0 | xxxx 
    OR | P1  | 1.5 | xxxx 
    WA | P1  | 1.0 | xxxx 
    VA | P2  | 1.2 | xxxx 

(. Estado/Producto/Distribuidor juntos forman la clave para la tabla 1 Estado/producto es la clave para la Tabla2)

Quiero encontrar todas las combinaciones Estado/producto/de versión que no están utilizando distribuidor X. (Así, el resultado en este ejemplo es la CA-P1-1.0, y VA-P2-1.2.)

¿Alguna sugerencia sobre una consulta para hacer esto?

+0

desde su segunda a la última frase, debería incluso TABLA2 estar involucrados en esta consulta? (excepto tal vez para obtener la versión del producto). – Tundey

+0

Creo que respondió su propia pregunta. Table2 es necesario para obtener la versión. –

Respuesta

24
SELECT 
    * 
FROM 
    Table2 T2 
WHERE 
    NOT EXISTS (SELECT * 
     FROM 
      Table1 T1 
     WHERE 
      T1.State = T2.State AND 
      T1.Product = T2.Product AND 
      T1.Distributor = 'X') 

Esto debería ser compatible con ANSI.

+0

Esto funciona en la mayoría de los sistemas SQL; EXCEPTO no funcionará en todas partes (aunque es más elegante donde funciona). –

+0

El uso de "SELECT 1 FROM" en la subconsulta (en lugar de "SELECT * FROM") puede evitar un escaneo de tabla innecesario. Aunque esperaría que el DBMS fuera lo suficientemente inteligente como para resolverlo por sí solo, al ver "EXISTS". – Tomalak

+1

Tengo esto con mi colega MVP de SQL Server todo el tiempo :-) El * se expande en el tiempo de compilación, bt colapsa trivialmente, pero no el tiempo de ejecución, dice. Él me mostró un artículo una vez. Vi a Itzak Ben-Gan hace un tiempo y dijo que * es más rápido. La elección es suya ... – gbn

1

SELECT * FROM tabla1 donde el estado no en (seleccione el estado de tabla1 donde distribuidor = 'X')

Probablemente no es el más inteligente, pero que debería funcionar.

+0

IN no es tan bueno como EXISTS, y no maneja la clave compuesta en estado/producto – gbn

+1

También, dependiendo de RDBMS 'NOT IN' no se comporta como se esperaría si' state' es anulable. –

8

En T-SQL:

SELECT DISTINCT Table2.State, Table2.Product, Table2.Version 
FROM Table2 
    LEFT JOIN Table1 ON Table1.State = Table2.State AND Table1.Product = Table2.Product AND Table1.Distributor = 'X' 
WHERE Table1.Distributor IS NULL 

No hay sub consultas requeridas.

Editar: Como indican los comentarios, DISTINCT no es necesario. ¡Gracias!

+0

No usaría distinct, pero de lo contrario esto es lo que quiere. – HLGEM

+0

Lo distinto probablemente hará que la consulta sea menos eficiente, pero nunca más eficiente. Depende del recuento relativo de filas de la tabla. El distcnt también fuerza un agregado que la consulta secundaria no necesita. – gbn

+1

El rendimiento y el comportamiento de esta consulta también dependen en gran medida de si 'Distribuidor' está cubierto por el índice utilizado en la combinación (si no puede ser necesaria una búsqueda o una operación de índice puede convertirse en una operación de índice agrupado) y si 'Distribuidor' es NULLable (en cuyo caso puede devolver las filas coincidentes que faltan un valor, además de las filas no coincidentes). –

1
SELECT DISTINCT t2.State, t2.Product, t2.Version 
FROM table2 t2 
JOIN table1 t1 ON t1.State = t2.State AND t1.Product = t2.Product 
       AND t1.Distributor <> 'X' 
1

En Oracle:

SELECT t2.State, t2.Product, t2.Version 
FROM Table2 t2, Table t1 
WHERE t1.State(+) = t2.State 
    AND t1.Product(+) = t2.Product 
    AND t1.Distributor(+) = :distributor 
    AND t1.State IS NULL 
Cuestiones relacionadas