AAI Agentic Handbook
Problem 100 · Data Engineering & Streaming

Parse and Evaluate a SQL WHERE Clause

HardClassic DSA & systems
01Problem

Given a WHERE expression with comparisons, AND/OR/NOT, IN lists, parentheses, numbers and quoted strings, compile it into a predicate over dict rows.

02Key insight

Tokenize with a regex, then recursive descent with one function per precedence level (OR < AND < NOT < comparison). Compile to closures once and reuse per row instead of re-walking the AST. NULL follows SQL three-valued logic: a comparison with NULL is UNKNOWN (None), which propagates through NOT/AND/OR (FALSE AND UNKNOWN = FALSE, TRUE OR UNKNOWN = TRUE); a row matches only if the result is TRUE, so NOT age < 20 still filters NULL ages.

03Solution

Try it first.

TimeO(L) to compile, O(size of expression) per row
SpaceO(L)
tests.py · 9 passing
tests.pypython17 lines
rows = [{"id": 1, "name": "O'Brien", "age": 40, "city": "SF"},
        {"id": 2, "name": "Lee", "age": 25, "city": "NYC"},
        {"id": 3, "name": "Kim", "age": None, "city": "LA"}]
q = lambda e: [r["id"] for r in rows if compile_where(e)(r)]
assert q("age >= 30 OR city = 'NYC' AND NOT age < 20") == [1, 2]
assert q("city IN ('LA', 'SF') AND (name = 'O''Brien' OR id = 3)") == [1, 3]
assert q("age <> 40") == [2]  # NULL comparison is UNKNOWN -> filtered
assert q("NOT age < 20") == [1, 2]  # NOT UNKNOWN is still UNKNOWN
assert q("NOT (age > 30 AND city = 'LA')") == [1, 2]  # row 3: NOT (UNKNOWN AND TRUE) = UNKNOWN
assert q("age > 30 OR city = 'LA'") == [1, 3]  # UNKNOWN OR TRUE = TRUE
assert compile_where("NOT city IN ('LA')")({"city": None}) is False
assert compile_where("NOT city IN ('LA', missing)")({"city": "SF"}) is False  # NOT IN with NULL in list
assert compile_where("age < 20 AND city = 'SF'")({"age": None, "city": "LA"}) is False
try:
    compile_where("age > AND 3"); assert False
except SyntaxError:
    pass
04Staff-level follow-up

How would a real engine evaluate this over a billion rows? Push predicates down to the scan, prune files/micro-partitions using min/max zone maps, and evaluate vectorized over columnar batches (or JIT-compile) instead of per-row Python closures.