sql >> Databáze >  >> RDS >> Oracle

Převod NOT IN na NOT EXISTS

Je to docela jednoduché, když to pochopíte:

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

Tento řádek v podstatě porovnává S.S_Id se všemi e.S_Id hodnoty, které pocházejí z poddotazu.

Nyní to změňte na NOT EXISTS a zadejte kontrolu rovnosti S.S_Id = e.S_Id , uvnitř poddotazu:

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

Menší možná změna je uvědomit si, že (SELECT e.S_Id ... ve skutečnosti nepotřebuje e.S_Id . Dílčí dotazy s EXISTS a NOT EXISTS stačí zkontrolovat, zda jsou vráceny řádky nebo ne, a na hodnotách sloupců nezáleží. Můžete zadat SELECT * nebo tam konstanta (SELECT 1 je běžné) nebo SELECT NULL nebo dokonce SELECT 1/0 (Ano, to bude fungovat!):

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

Dalším důležitým aspektem je, že když provedete převod tímto způsobem, (zdánlivě ekvivalentní) NOT EXISTS a NOT IN zápisy dotazu jsou skutečně ekvivalentní, pouze pokud jsou oba S_Id sloupce nemají hodnotu null. Pokud e.S_Id sloupec má hodnotu null, NOT IN může způsobit, že celý dotaz nevrátí vůbec žádné řádky (protože x NOT IN (a, b, c, ...) je ekvivalentní x<>a AND x<>b AND ... a tato podmínka nemůže být pravdivá, když jeden z a,b,c... je NULL .)

Z podobných důvodů budete mít jiné výsledky, pokud s.S_Id má nulovou hodnotu (v tomto případě to není příliš pravděpodobné, protože se pravděpodobně jedná o primární klíč, ale v jiných případech na tom záleží.)

Téměř vždy je tedy lepší použít NOT EXISTS , protože se chová odlišně, i když je v každém sloupci povolena hodnota Null (S.S_Id = e.S_Id check zahodí řádky s null dříve) a toto chování je obvykle žádoucí. V otázce je mnoho podrobností: NENÍ IN vs. NEEXISTUJE , v odpovědi @Martin Smith. Najdete zde také způsoby, jak převést NOT IN na NOT EXISTS a zachovat nulové (nepříjemné) chování.



  1. mezipaměť dotazů nefunguje

  2. Přístup pomocí Microsoft SQL Server – import velkých datových sad pomocí SSIS

  3. Uložená procedura v Oracle s chybou PLS-00428

  4. Uzamčení řádku MySQL INNODB v PHP