Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Konwersja NOT IN na NOT EXISTS

To dość proste, kiedy to opanujesz:

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);

Ta linia zasadniczo porównuje S.S_Id ze wszystkimi e.S_Id wartości, które pochodzą z podzapytania.

Teraz zmień to na NOT EXISTS i umieść kontrolę równości S.S_Id = e.S_Id , wewnątrz podzapytania:

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);

Drobną możliwą zmianą jest uświadomienie sobie, że (SELECT e.S_Id ... tak naprawdę nie potrzebuje e.S_Id . Podzapytania z EXISTS i NOT EXISTS po prostu sprawdź, czy są zwracane wiersze, czy nie, a wartości kolumn nie mają znaczenia. Możesz umieścić SELECT * lub stała tam (SELECT 1 jest powszechne) lub SELECT NULL lub nawet SELECT 1/0 (Tak, to zadziała!):

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);

Inną ważną kwestią jest to, że podczas konwersji w ten sposób (pozornie równoważny) NOT EXISTS i NOT IN zapisy zapytania są naprawdę równoważne tylko wtedy, gdy oba S_Id kolumny nie mają wartości null. Jeśli e.S_Id kolumna jest dopuszczalna, NOT IN może spowodować, że całe zapytanie nie zwróci żadnych wierszy (ponieważ x NOT IN (a, b, c, ...) jest odpowiednikiem x<>a AND x<>b AND ... a warunek ten nie może być spełniony, gdy jeden z a,b,c... jest NULL .)

Z podobnych powodów uzyskasz różne wyniki, jeśli s.S_Id jest wartością null (w tym przypadku jest to mało prawdopodobne, ponieważ jest to prawdopodobnie klucz podstawowy, ale w innych przypadkach ma znaczenie).

Więc prawie zawsze lepiej jest użyć NOT EXISTS , ponieważ zachowuje się inaczej, nawet jeśli którakolwiek kolumna dopuszcza wartość null (S.S_Id = e.S_Id check usunie wiersze z wartością null wcześniej) i zwykle to zachowanie jest pożądane. W pytaniu jest wiele szczegółów: NIE W vs NIE ISTNIEJE , w odpowiedzi @Martin Smith. Znajdziesz tam również sposoby na przekonwertowanie NOT IN na NOT EXISTS i zachowaj zerowe (nieprzyjemne) zachowanie.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Generowanie bufora na podstawie warunków w skrypcie Oracle SQL

  2. Dlaczego CONNECT BY LEVEL w tabeli zwraca dodatkowe wiersze?

  3. Oracle :Eksportuj zestaw wyników instrukcji SELECT jako INSERT SQL Statements podobny do eksportu programisty SQL

  4. Używanie funkcji LAG lub Other w klauzuli SUM

  5. Mapowanie pól w Oracle SQL Loader