In SQL queries, IN and EXISTS are interchangeable. Many of us assume therefore, that NOT IN and NOT EXISTS are also interchangeable.
A big mistake.
See how NOT IN and NOT EXISTS behave differently in this small example.
Writing a query to find the number of employees in emp table who are not managers. The logic used is: get count where the employee id is not present in as mgr id in the same table.
OK, that says there are no such employees. Let’s try it with NOT EXISTS now.
Whoa! 8 such employees! Which answer is correct?
Let’s verify with the help of a flag against each employee – yes_mgr or no_mgr. We calculate this flag with help of the CASE statement.
It turns out that there actually are eight employees who are flagged no_mgr, so the NOT EXISTS version is all right.
A big mistake.
See how NOT IN and NOT EXISTS behave differently in this small example.
Writing a query to find the number of employees in emp table who are not managers. The logic used is: get count where the employee id is not present in as mgr id in the same table.
The NOT IN version:
SQL> -- Using NOT IN SQL> -- Count employees who SQL> -- are not managers SQL> select count (*) 2 from emp e1 3 where e1.empno not in 4 ( select e2.mgr 5 from emp e2); COUNT (*) ---------- 0 |
The NOT EXISTS version:
| SQL> -- Using NOT EXISTS SQL> -- Count employees who SQL> -- are not managers SQL> select count (*) 2 from emp e1 3 where not exists 4 ( select 'Y' 5 from emp e2 6 where e2.mgr = e1.empno) COUNT (*) ---------- 8 |
Let’s verify with the help of a flag against each employee – yes_mgr or no_mgr. We calculate this flag with help of the CASE statement.
SQL> select e.empno 2 , e.mgr 3 , case when 4 ( select 'Y' from emp m 5 where m.mgr = e.empno 6 and rownum = 1) is null 7 then 'no_mgr' 8 else 'yes_mgr' 9 end is_mgr 10 from emp e; EMPNO MGR IS_MGR ---------- ---------- ------- 7369 7902 no_mgr 7499 7698 no_mgr 7521 7698 no_mgr 7566 7839 yes_mgr 7654 7698 no_mgr 7698 7839 yes_mgr 7782 7839 yes_mgr 7788 7566 yes_mgr 7839 yes_mgr 7844 7698 no_mgr 7876 7788 no_mgr 7900 7698 no_mgr 7902 7566 yes_mgr 7934 7782 no_mgr 14 rows selected. |
Why does NOT IN give a “wrong” result?!
Well, it isn’t a wrong result, that’s how it is supposed to work! The column ‘mgr’ in the emp table is nullable. As per Oracle’s treatment of NULLs:- where 3 in (3, null) is TRUE as 3 is in (3).
- where 3 not in (1, null) is UNKNOWN as it is not known whether 3 is in null or not.
Conclusion
- NOT IN and NOT EXISTS are not identical if the subquery can potentially return nulls.
- Use NOT IN only if you are 100% certain that the subquery will not return NULLs.
0 comments:
Post a Comment