Sometimes the question is not “what is the other table’s value?” but “does any row exist?” or “how does this number compare to a whole set?” DB2 answers the first with EXISTS / NOT EXISTS and the second with quantified predicates: ANY, SOME, and ALL. This page covers IBM’s truth rules, empty subqueries, nulls, and when EXISTS is safer than IN.
The EXISTS predicate tests for the existence of certain rows. The fullselect can specify any number of columns. The values returned are ignored—IBM recommends SELECT * for convenience. The outer SELECT list of that fullselect must not contain an array value.
12345678SELECT EMPNO FROM DSN8C10.EMP X WHERE EXISTS ( SELECT * FROM DSN8C10.EMP WHERE X.WORKDEPT = WORKDEPT AND SALARY < 20000 );
IBM’s example lists employee numbers of everyone who works in a department where at least one employee has a salary less than 20000. Like many EXISTS predicates, this one is correlated: the inner query refers to X.WORKDEPT from the outer row.
Correlation is not required. An uncorrelated EXISTS is a yes/no about a set that does not depend on the outer row (for example “does table T have any row at all?”). Correlated EXISTS is the usual “does this parent have a matching child?” pattern.
Unlike NULL, LIKE, and IN, EXISTS has no form that contains the word NOT inside the predicate. To negate it, precede EXISTS with the logical operator NOT:
1234567SELECT D.DEPTNO, D.DEPTNAME FROM DSN8C10.DEPT D WHERE NOT EXISTS ( SELECT * FROM DSN8C10.EMP E WHERE E.WORKDEPT = D.DEPTNO );
NOT EXISTS is false when EXISTS is true, and true when EXISTS is false. Because EXISTS itself is never UNKNOWN, NOT EXISTS is also never UNKNOWN. That is why it is the safe rewrite of NOT IN (SELECT nullable_col …) for anti-joins.
Write the inner predicate as an equality on the keys you care about. Do not add extra OR IS NULL inside the subquery unless that is the business rule—those extra rows would make EXISTS true and hide the department.
The optimizer may rewrite either form as a join. You still write the form that matches the question and stays correct when a column can be null.
A quantified predicate compares a value or a row with a collection of values. The collection is a fullselect. When you specify a single expression, the fullselect must return one column and any number of values (null or not). When you specify a row-value-expression, the fullselect must return the same number of columns.
| Form | Meaning | Empty subquery |
|---|---|---|
| = ANY / = SOME | Equal to at least one value (same as IN) | FALSE |
| <> ALL | Not equal to every value (same as NOT IN) | TRUE |
| > ALL | Greater than every returned value | TRUE |
| > ANY / > SOME | Greater than at least one returned value | FALSE |
| < ALL | Less than every returned value | TRUE |
SOME and ANY are synonyms. The predicate is:
1234567891011-- Employees who earn more than at least one employee in E11 SELECT EMPNO, LASTNAME, SALARY FROM DSN8C10.EMP WHERE SALARY > ANY ( SELECT SALARY FROM DSN8C10.EMP WHERE WORKDEPT = 'E11' ); -- Same idea as IN WHERE WORKDEPT = ANY (SELECT DEPTNO FROM DSN8C10.DEPT WHERE LOCATION = 'DALLAS');
IBM maps expression IN (fullselect) to expression = ANY (fullselect) and NOT IN to <> ALL.
ALL requires the relationship to hold for every returned value:
12345678-- Salary greater than every salary in department E11 SELECT EMPNO, LASTNAME, SALARY FROM DSN8C10.EMP WHERE SALARY > ALL ( SELECT SALARY FROM DSN8C10.EMP WHERE WORKDEPT = 'E11' );
Two beginner shocks:
Other comparison operators work the same way: <, <=, >=, <>. Prefer <> over not-sign spellings in new SQL.
You can compare a row to a set of rows: (WORKDEPT, JOB) = ANY (SELECT …) or <> ALL. Column counts and types must match. This is the quantified form of row-value IN.
EXISTS often becomes a semi-join: Db2 can stop at the first matching inner row. Correlated EXISTS with a supporting index on the inner join columns is a classic good pattern. Quantified predicates with noncorrelated subqueries may be merged or materialized. Wrapping the outer column in a function still hurts matching. For “no children,” compare EXPLAIN of NOT EXISTS versus a LEFT JOIN … WHERE key IS NULL; both are valid anti-joins.
EXISTS is asking “is there at least one cookie in the jar?” You do not care which cookie or how many—only whether the jar is empty. NOT EXISTS is “the jar is empty.” ANY/SOME is “is my cookie bigger than at least one cookie in that other jar?” ALL is “is my cookie bigger than every cookie in that jar?” If the other jar has no cookies, “bigger than every cookie” is a silly yes. If someone put a mystery unlabeled cookie (NULL) in the jar, “bigger than every cookie” cannot be a clear yes.
IBM’s EXISTS discussion says the values are ignored and SELECT * is convenient. SELECT 1 is a common style and is also fine. Do not SELECT a huge LOB “for EXISTS”—the engine should not need the value, but you should not tempt it.
EXISTS is a predicate, not a scalar. In a select list use a CASE: CASE WHEN EXISTS (…) THEN 'Y' ELSE 'N' END, or a scalar subquery that returns a count.
COL = ALL (set) is true when every value in the set equals COL (or the set is empty). If the set has two different values, it is false. That is rarely a business question; = ANY or a join is more common.
1. When is EXISTS (subquery) true?
2. How do you write NOT EXISTS in Db2?
3. What does = ANY (fullselect) mean?
4. If a subquery is empty, what is COL > ALL (subquery)?
5. Why prefer NOT EXISTS over NOT IN for a nullable subquery column?