A basic predicate in DB2 for z/OS is two compatible expressions joined by =, <>, <, >, <=, or >=. The overview pages show the symbols. This page is the depth: three-valued results, CHAR padding, row-value comparisons, datetime order, distinct types, and why = is the predicate the optimizer loves while <> often is not.
| Operator | TRUE when | Notes |
|---|---|---|
| = | Left and right are equal | Best matching predicate on an indexed column |
| <> | Left and right are not equal | UNKNOWN if either is null; often not matching |
| < | Left is ordered before right | Range matching when the column is the start of an index |
| > | Left is ordered after right | Same range idea as < |
| <= | Less than or equal | Inclusive upper bound; pairs with BETWEEN |
| >= | Greater than or equal | Inclusive lower bound |
12345SELECT EMPNO, LASTNAME, SALARY FROM DSN8C10.EMP WHERE SALARY >= 50000 AND SALARY <> 52750 AND WORKDEPT = 'A00';
Operands must be compatible types (or implicitly convertible). You cannot compare a BLOB to an INTEGER. Distinct types compare to themselves; comparing a distinct type to its source type usually needs CAST. Binary strings compare as bytes; character strings follow CCSID conversion then the collating rules for that encoding.
= is identity of values, not identity of rows. WORKDEPT = 'A00' is TRUE when the department code is exactly that string under character comparison rules. It is the predicate you want on join keys and on indexed lookup columns. Host variables should match the column type so Db2 does not add a cast that turns a matching predicate into a stage 2 residual.
For numbers, 5 = 5.0 is TRUE after numeric comparison (DECIMAL versus INTEGER conversion). For floats, equality is brittle: DOUBLE calculations that “look like” 0.1 may not equal DECIMAL 0.1. Compare money as DECIMAL.
<> is TRUE when the values differ and both are non-null. Write <> in new SQL. !=, ^=, and ¬= are compatibility spellings; ¬ in particular is a code-page hazard when source moves between EBCDIC and ASCII tools.
NOT (COL = 5) is the same three-valued result as COL <> 5: if COL is null, the inner = is UNKNOWN, NOT UNKNOWN is still UNKNOWN. You do not get the null rows. To include nulls you must say COL <> 5 OR COL IS NULL (or use IS DISTINCT FROM).
Order is type-specific:
<= and >= include equality. A closed range is COL >= :lo AND COL <= :hi, which is what BETWEEN means. An open range uses < or > on one side (for example timestamps: TS >= :day AND TS < :day + 1 DAY).
Truth table for COL = 5 when COL may be null:
WHERE and HAVING keep TRUE only. CHECK constraints treat UNKNOWN as passing (the row is allowed) unless you write IS NOT NULL. JOIN ON is also a search condition: ON T1.K = T2.K does not match null keys to each other. That is why outer joins produce nulls on the non-preserved side instead of “null equals null” matches.
123456-- Does not return rows where COMM is null SELECT EMPNO FROM DSN8C10.EMP WHERE COMM < 1000; -- Null-safe “different from 1000, including missing commission” SELECT EMPNO FROM DSN8C10.EMP WHERE COMM IS DISTINCT FROM 1000;
(HIREDATE, EMPNO) > (:d, :e) compares like a composite sort key: HIREDATE first, then EMPNO when dates tie. Equality is pairwise. This form is useful for keyset pagination (“next page after this bookmark”) when a single column is not unique.
12345SELECT EMPNO, LASTNAME, HIREDATE FROM DSN8C10.EMP WHERE (HIREDATE, EMPNO) > (:LAST_DATE, :LAST_EMPNO) ORDER BY HIREDATE, EMPNO FETCH FIRST 20 ROWS ONLY;
A subquery on the other side of a basic predicate must be scalar (one column, at most one row) unless you are using a row-value versus a fullselect that returns one row of matching degree. Multiple rows from a scalar subquery are SQLCODE -811. Use ANY/ALL or IN when the set can have many rows.
A matching predicate can probe an index. Stage 1 predicates can be applied on the index or data manager without the full stage 2 residual evaluator. Rough beginner map:
Details belong on the indexable versus stage 2 page. The takeaway here: write comparisons so the column stands alone on one side whenever you care about access path.
Comparison predicates are questions you ask about two fridge magnets: “Are they the same letter?” (=), “Are they different?” (<>), “Is this one later in the alphabet?” (>). If one magnet is missing (NULL), you do not answer yes or no—you shrug (UNKNOWN), and the WHERE bouncer only lets in the kids who answered yes. Two magnets that look like A, even if one has invisible blank stickers on the end (CHAR padding), still count as the same letter. Measuring “not equal” is a weaker flashlight for finding a magnet in a sorted drawer than asking for the exact letter.
1. What is a basic comparison predicate?
2. What is the result of SALARY > NULL?
3. Is CHAR(3) value 'A' equal to VARCHAR value 'A'?
4. Which not-equal spelling should new SQL use?
5. Is COL <> 5 typically as index-friendly as COL = 5?