sql >> Base de Datos >  >> RDS >> Oracle

Convertir NOT IN a NOT EXISTS

Es bastante simple, cuando le coges el tranquillo:

SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
WHERE s.S_Sex = 'F'
AND S.S_Id NOT IN(SELECT e.S_Id           -- take this line
        FROM ENROLLMENT e
        WHERE e.Mark < 70);

Esa línea básicamente compara S.S_Id con todos los e.S_Id valores que provienen de la subconsulta.

Ahora cámbialo a NOT EXISTS y poner una verificación de igualdad S.S_Id = e.S_Id , dentro de la subconsulta:

SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
WHERE s.S_Sex = 'F'
AND NOT EXISTS (SELECT e.S_Id          
        FROM ENROLLMENT e
        WHERE (e.Mark < 70)       -- if this is complex, you'll need parentheses
        AND S.S_Id = e.S_Id);

El cambio menor posible es darse cuenta de que (SELECT e.S_Id ... realmente no necesita el e.S_Id . Subconsultas con EXISTS y NOT EXISTS simplemente verifique si hay filas devueltas o no y los valores de las columnas no importan. Puedes poner SELECT * o una constante allí (SELECT 1 es común) o SELECT NULL o incluso SELECT 1/0 (¡Sí, eso funcionará!):

SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
WHERE s.S_Sex = 'F'
AND NOT EXISTS (SELECT 1
        FROM ENROLLMENT e
        WHERE e.Mark < 70  
        AND S.S_Id = e.S_Id);

Otra consideración importante es que cuando realiza la conversión de esta manera, el (aparentemente equivalente) NOT EXISTS y NOT IN las escrituras de una consulta son realmente equivalentes solo si ambos S_Id las columnas no son anulables. Si el e.S_Id la columna es anulable, el NOT IN puede dar como resultado que la consulta completa no devuelva ninguna fila (porque x NOT IN (a, b, c, ...) es equivalente a x<>a AND x<>b AND ... y esa condición no puede ser verdadera cuando uno de los a,b,c... es NULL .)

Por razones similares, obtendrá resultados diferentes si s.S_Id es anulable (eso no es muy probable en este caso, ya que probablemente sea la clave principal, pero en otros casos es importante).

Así que casi siempre es mejor usar NOT EXISTS , ya que se comporta de manera diferente incluso si cualquiera de las columnas admite valores NULL (el S.S_Id = e.S_Id check descartará las filas con nulo anterior) y, por lo general, este comportamiento es el deseado. Hay muchos detalles en la pregunta: NO EN vs NO EXISTE , en la respuesta de @Martin Smith. También encontrará formas de convertir el NOT IN a NOT EXISTS y mantener el comportamiento relacionado nulo (desagradable).