Descargo de responsabilidad: he resuelto el problema (creo), pero quería agregar este problema a Stack Overflow ya que no podía (fácilmente) encontrarlo en ningún lado. Además, alguien podría tener una mejor respuesta que yo.
Tengo una base de datos donde varias tablas hacen referencia a una tabla "Común". Quería ver qué registros de la tabla común quedaron huérfanos (es decir, no tenía 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 registros. Por qué no?
(Esto es SQL Server, si es importante).
sql
sql-server
tsql
Jeremy Stein
fuente
fuente
Respuestas:
Actualizar:
Estos artículos en mi blog describen las diferencias entre los métodos con más detalle:
NOT IN
frente aNOT EXISTS
frenteLEFT JOIN / IS NULL
:SQL Server
NOT IN
frente aNOT EXISTS
frenteLEFT JOIN / IS NULL
:PostgreSQL
NOT IN
frente aNOT EXISTS
frenteLEFT JOIN / IS NULL
:Oracle
NOT IN
frente aNOT EXISTS
frenteLEFT JOIN / IS NULL
:MySQL
Hay tres formas de hacer una consulta de este tipo:
LEFT JOIN / IS NULL
:NOT EXISTS
:NOT IN
:Cuando
table1.common_id
no es anulable, todas estas consultas son semánticamente iguales.Cuando es anulable,
NOT IN
es diferente, ya queIN
(y, por lo tantoNOT IN
) regresaNULL
cuando un valor no coincide con nada en una lista que contiene unNULL
.Esto puede ser confuso pero puede volverse más obvio si recordamos la sintaxis alternativa para esto:
El resultado de esta condición es un producto booleano de todas las comparaciones dentro de la lista. Por supuesto, un solo
NULL
valor produce elNULL
resultado que también representa el resultado completoNULL
.Nunca podemos decir definitivamente que
common_id
no es igual a nada de esta lista, ya que al menos uno de los valores lo esNULL
.Supongamos que tenemos estos datos:
LEFT JOIN / IS NULL
yNOT EXISTS
volverá3
,NOT IN
volverá nada (ya que siempre evaluará a cualquieraFALSE
oNULL
).En
MySQL
, en el caso de la columna no anulable,LEFT JOIN / IS NULL
yNOT IN
son un poco (varios por ciento) más eficientes queNOT EXISTS
. Si la columna es anulable,NOT EXISTS
es la más eficiente (nuevamente, no mucho).En
Oracle
, las tres consultas producen los mismos planes (anANTI JOIN
).En
SQL Server
,NOT IN
/NOT EXISTS
son más eficientes, yaLEFT JOIN / IS NULL
que no puede ser optimizado para unANTI JOIN
por su optimizador.En
PostgreSQL
,LEFT JOIN / IS NULL
yNOT EXISTS
son más eficientes queNOT IN
, sinusoidales, están optimizados para unAnti Join
, mientras que losNOT IN
usoshashed subplan
(o incluso un planosubplan
si la subconsulta es demasiado grande para el hash)fuente
NOT EXISTS
evalúa como VERDADERO si la consulta en su interior devuelve alguna fila.SELECT NULL
bien podría serSELECT *
oSELECT 1
cualquier otra cosa, elNOT EXISTS
predicado no mira los valores de las filas, solo los cuenta.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!
fuente
common_id not in
, todavía podemos tenercommon_id
valor que esNULL
. Entonces, ¿el problema de no obtener resultados aún persiste?Table1 o Table2 tiene algunos valores nulos para common_id. Utilice esta consulta en su lugar:
fuente
fuente
Justo al lado de la parte superior de mi cabeza...
Hice algunas pruebas y aquí estaban mis resultados con la respuesta de wrt @ patmortech y los comentarios de @ rexem.
Si Table1 o Table2 no están indexados en commonID, obtiene un escaneo de la tabla, pero la consulta de @ patmortech sigue siendo el doble de rápida (para una tabla maestra de filas de 100K).
Si ninguno de ellos está indexado en commonID, obtiene 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.
fuente
fuente
Supongamos que estos valores para common_id:
Queremos que la fila en común 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:
Eso es equivalente a:
Aquí es donde empieza el problema. Cuando se compara con un nulo, la respuesta es desconocida . Entonces la consulta se reduce a
falso o desconocido es desconocido:
verdadero y no desconocido también es desconocido:
La condición where no devuelve registros donde el resultado es desconocido, por lo que no recuperamos registros.
Una forma de lidiar con esto es usar el operador exist en lugar de in. Exists nunca devuelve desconocido porque opera en filas en lugar de columnas. (Existe una fila o no existe; ¡nada de esta ambigüedad nula a nivel de fila!)
fuente
esto funcionó para mí :)
fuente
NOT IN
actuar allí?fuente
Tenía un ejemplo en el que estaba buscando y debido a que una tabla contenía el valor como un doble, la otra como una cadena, no coincidirían (o no coincidirían sin un molde). Pero solo NO EN . Como SELECT ... IN ... funcionó. Extraño, pero pensé que compartiría en caso de que alguien más se encuentre con esta solución simple.
fuente
Siga el siguiente ejemplo para comprender el tema anterior:
También puedes visitar el siguiente enlace para saber Anti unirse
Pero si usamos
NOT IN
en ese caso no obtenemos ningún dato.Esto sucede cuando (
select department_id from hr.employees
) devuelve un valor nulo y toda la consulta se evalúa como falsa. Podemos verlo si cambiamos el SQL ligeramente como se muestra a continuación y manejamos valores nulos con la función NVL.Ahora estamos obteniendo datos:
Nuevamente estamos obteniendo datos ya que hemos manejado el valor nulo con la función NVL.
fuente