tutorial transact queries from for examples ejemplos sql sql-server tsql

transact - SQL "select where not in subquery" no arroja resultados



where condition sql server (9)

Descargo de responsabilidad: He descubierto el problema (creo), pero quería agregar este problema a Stack Overflow ya que no pude (fácilmente) encontrarlo en ningún lado. Además, alguien podría tener una mejor respuesta que yo.

Tengo una base de datos donde otras tablas hacen referencia a una tabla "Común". Quería ver qué registros en la tabla común se quedaron huérfanos (es decir, no tenían referencias de ninguna de las otras tablas).

Ejecuté esta consulta:

select * from Common where common_id not in (select common_id from Table1) and common_id not in (select common_id from Table2)

Sé que hay registros huérfanos, pero no se devolvieron los registros. Por qué no?

(Esto es SQL Server, si es importante)


Justo al lado de la parte superior de mi cabeza...

select c.commonID, t1.commonID, t2.commonID from Common c left outer join Table1 t1 on t1.commonID = c.commonID left outer join Table2 t2 on t2.commonID = c.commonID where t1.commonID is null and t2.commonID is null

Realicé algunas pruebas y aquí estaban mis resultados, la respuesta de wrt @ patmortech y los comentarios de @rexem.

Si Table1 o Table2 no están indexados en commonID, se obtiene un escaneo de tabla, pero la consulta de @patmortech sigue siendo dos veces más rápida (para una tabla maestra de 100K filas).

Si ninguno de los dos está indexado en commonID, obtendrá dos escaneos de tabla y la diferencia es insignificante.

Si ambos están indexados en commonID, la consulta "no existe" se ejecuta en 1/3 del tiempo.


Si desea que el mundo sea un lugar booleano de dos valores, debe evitar el caso nulo (tercer valor) usted mismo.

No escriba cláusulas IN que permitan nulos en el lado de la lista. ¡Filtralos!

common_id not in ( select common_id from Table1 where common_id is not null )


Supongamos estos valores para common_id:

Common - 1 Table1 - 2 Table2 - 3, null

Queremos que la fila en Common regrese, porque no existe en ninguna de las otras tablas. Sin embargo, el nulo arroja una llave inglesa.

Con esos valores, la consulta es equivalente a:

select * from Common where 1 not in (2) and 1 not in (3, null)

Eso es equivalente a:

select * from Common where not (1=2) and not (1=3 or 1=null)

Aquí es donde empieza el problema. Al comparar con un valor nulo, la respuesta es desconocida . Entonces, la consulta se reduce a

select * from Common where not (false) and not (false or unkown)

falso o desconocido es desconocido:

select * from Common where true and not (unknown)

verdadero y no desconocido también es desconocido:

select * from Common where unknown

La condición where no devuelve registros donde el resultado no se conoce, por lo que no recuperamos ningún registro.

Una forma de lidiar con esto es utilizar el operador exists en lugar de in. Exists nunca devuelve desconocido porque opera en filas en lugar de en columnas. (Una fila existe o no existe, ¡ninguna de esta ambigüedad nula en el nivel de la fila!)

select * from Common where not exists (select common_id from Table1 where common_id = Common.common_id) and not exists (select common_id from Table2 where common_id = Common.common_id)


Table1 o Table2 tiene algunos valores nulos para common_id. Use esta consulta en su lugar:

select * from Common where common_id not in (select common_id from Table1 where common_id is not null) and common_id not in (select common_id from Table2 where common_id is not null)


esto funcionó para mí :)

seleccionar * de Común

dónde

common_id no está en (seleccione ISNULL (common_id, ''dummy-data'') de la Tabla1)

y common_id no está en (seleccione ISNULL (common_id, ''dummy-data'') de la Tabla 2)


Actualizar:

Estos artículos en mi blog describen las diferencias entre los métodos en más detalle:

Hay tres formas de hacer una consulta de este tipo:

  • LEFT JOIN / IS NULL :

    SELECT * FROM common LEFT JOIN table1 t1 ON t1.common_id = common.common_id WHERE t1.common_id IS NULL

  • NOT EXISTS :

    SELECT * FROM common WHERE NOT EXISTS ( SELECT NULL FROM table1 t1 WHERE t1.common_id = common.common_id )

  • NOT IN :

    SELECT * FROM common WHERE common_id NOT IN ( SELECT common_id FROM table1 t1 )

Cuando table1.common_id no puede table1.common_id , todas estas consultas son semánticamente las mismas.

Cuando es anulable, NOT IN es diferente, ya que IN (y, por lo tanto, NOT IN ) devuelve NULL cuando un valor no coincide con nada en una lista que contiene un NULL .

Esto puede ser confuso, pero puede volverse más obvio si recordamos la sintaxis alternativa para esto:

common_id = ANY ( SELECT common_id FROM table1 t1 )

El resultado de esta condición es un producto booleano de todas las comparaciones dentro de la lista. Por supuesto, un único valor NULL produce el resultado NULL que representa el resultado NULL también.

Nunca podemos decir definitivamente que common_id no es igual a nada de esta lista, ya que al menos uno de los valores es NULL .

Supongamos que tenemos estos datos:

common -- 1 3 table1 -- NULL 1 2

LEFT JOIN / IS NULL y NOT EXISTS devolverá 3 , NOT IN no devolverá nada (ya que siempre se evaluará como FALSE o NULL ).

En MySQL , en el caso de una columna que no admite nulos, LEFT JOIN / IS NULL y NOT IN son un poco (varios por ciento) más eficientes que NOT EXISTS . Si la columna es nulable, NOT EXISTS es la más eficiente (nuevamente, no mucho).

En Oracle , las tres consultas producen los mismos planes ( ANTI JOIN ).

En SQL Server , NOT IN / NOT EXISTS es más eficiente, ya que LEFT JOIN / IS NULL no se puede optimizar a ANTI JOIN por su optimizador.

En PostgreSQL , LEFT JOIN / IS NULL y NOT EXISTS son más eficientes que NOT IN , ya que están optimizados para un Anti Join , mientras que NOT IN utiliza un hashed subplan (o incluso un subplan simple si la subconsulta es demasiado grande para hash)


SELECT T.common_id FROM Common T LEFT JOIN Table1 T1 ON T.common_id = T1.common_id LEFT JOIN Table2 T2 ON T.common_id = T2.common_id WHERE T1.common_id IS NULL AND T2.common_id IS NULL


select * from Common c where not exists (select t1.commonid from table1 t1 where t1.commonid = c.commonid) and not exists (select t2.commonid from table2 t2 where t2.commonid = c.commonid)


select *, (select COUNT(ID) from ProductMaster where ProductMaster.CatID = CategoryMaster.ID) as coun from CategoryMaster