Evaluate Boolean Expression
Evaluate Boolean Expression
An expression like x > y stores its two sides as names (left_operand, right_operand), so you can only evaluate it after replacing each name with its number — and the technique that does this is self-joining the lookup table once per operand: join Variables as v1 to resolve the left name and again as v2 to resolve the right name, giving you two numbers on one row that a CASE on operator can then compare.
The problem
Table Variables(name PK, value INT) stores variables. Table Expressions(left_operand, operator, right_operand) stores boolean expressions where operator is one of <, >, = and both operands are names guaranteed to exist in Variables. For each row, emit true or false.
The one technique worth naming: join the lookup table twice
The whole puzzle reduces to a single recurring SQL pattern. A row in Expressions holds two foreign keys into the same parent table — left_operand and right_operand both point at Variables.name. You cannot resolve both with one join, because one join binds Variables to exactly one of the two columns. So you reference the parent table twice under two aliases: v1 matched on the left name, v2 matched on the right name. Each alias is an independent copy of the same physical table; the aliases are what let the optimizer treat them as two separate inputs to the join.
This is the same shape as resolving manager_id and mentor_id on an employee row, or origin and destination on a flight row. Whenever one row carries two references into the same table, the answer is two aliased joins — not a subquery per column, not a self-join on equality of rows.
The full query
SELECT e.left_operand,
e.operator,
e.right_operand,
CASE e.operator
WHEN '>' THEN IF(v1.value > v2.value, 'true', 'false')
WHEN '<' THEN IF(v1.value < v2.value, 'true', 'false')
WHEN '=' THEN IF(v1.value = v2.value, 'true', 'false')
END AS value
FROM Expressions e
JOIN Variables v1 ON e.left_operand = v1.name
JOIN Variables v2 ON e.right_operand = v2.name;Standard-SQL equivalent if your engine lacks IF: replace IF(cond,'true','false') with CASE WHEN cond THEN 'true' ELSE 'false' END. Note CASE e.operator WHEN ... dispatches on the operator string; the inner test does the actual numeric comparison between the two resolved values.
Worked example, traced step by step
Inputs:
| Variables.name | Variables.value |
|---|---|
| x | 66 |
| y | 77 |
| left_operand | operator | right_operand |
|---|---|---|
| x | > | y |
| x | < | y |
| x | = | y |
| y | > | x |
| y | < | x |
| x | = | x |
After both joins resolve each name to a number, then the CASE fires:
| row | v1.value (left) | v2.value (right) | operator branch | test | value |
|---|---|---|---|---|---|
| x > y | 66 | 77 | WHEN '>' | 66 > 77 | false |
| x < y | 66 | 77 | WHEN '<' | 66 < 77 | true |
| x = y | 66 | 77 | WHEN '=' | 66 = 77 | false |
| y > x | 77 | 66 | WHEN '>' | 77 > 66 | true |
| y < x | 77 | 66 | WHEN '<' | 77 < 66 | false |
| x = x | 66 | 66 | WHEN '=' | 66 = 66 | true |
The last row, x = x, is the case that breaks the naive shortcut below: both operands resolve through the same alias only by coincidence of value — they are still resolved independently by v1 and v2.
Why the naive version is wrong
The tempting mistake is a single join, then comparing against a correlated subquery per operand:
-- WRONG (or at best fragile): one join, subquery for the other side
SELECT e.left_operand, e.operator, e.right_operand,
IF(v.value > (SELECT value FROM Variables WHERE name = e.right_operand),
'true','false') AS value -- only handles '>'
FROM Expressions e
JOIN Variables v ON e.left_operand = v.name;Two failure modes. First, it only resolves one operand through the join; the other becomes a per-row scalar subquery, so the optimizer often re-scans Variables for every expression row instead of doing one hash/merge join over two aliases. Second, people writing it usually hard-code a single comparison and forget the operator dispatch. The double-aliased join puts both values side by side on one row, so a single CASE operator covers all three operators cleanly and the planner sees two ordinary joins it can optimize.
Pitfalls
- Forgetting the alias and writing a self-join on row equality.
JOIN Variables v ON ...referenced once cannot supply both sides. You need two distinct aliases (v1,v2); reusing one name is a syntax error, andVariables JOIN Variableswithout aliases is ambiguous. - Using
=as assignment instead of comparison. In SQLv1.value = v2.valueinside a predicate is a boolean test, which is what you want — but in some dialects double-check you are not accidentally inside a context expecting an update. - NULL operands. The problem guarantees every operand exists in
Variables, so anINNER JOINis correct. If that guarantee did not hold, an inner join would silently drop the expression row; you would needLEFT JOINand decide what an unresolved operand evaluates to. - Missing an operator branch. If the
CASEomits one of<,>,=, that row returnsNULLforvaluerather than erroring — an easy silent bug. Cover all enum values or add anELSE. - Type coincidence on string compare. Compare
v1.valuetov2.value(the integers), never the operand names — comparing names would test'x' = 'y'as strings, which is always the wrong question.
Takeaways
- When one row holds two foreign keys into the same table, resolve them by joining that table once per reference under distinct aliases — this is the reusable pattern, not a trick specific to this puzzle.
- Aliasing makes one physical table behave as two independent join inputs; the optimizer can then do two ordinary joins instead of repeated correlated subqueries.
- Bring both resolved values onto one row first, then let a single
CASE operatordo the comparison — separating resolution from evaluation keeps the logic flat and complete. - With a guaranteed-present FK,
INNER JOINis correct and faster; reach forLEFT JOINonly when an operand might be missing.
Based on LeetCode 1440 “Evaluate Boolean Expression”. Mechanism, double-aliased-join framing, traced example, and pitfalls re-authored and deepened for this guide; SQL verified against MySQL 8 semantics (IF/CASE) and ANSI SQL CASE-expression rules. Self-join-on-aliases pattern cross-referenced with Joe Celko, “SQL for Smarties,” and the PostgreSQL documentation on table aliases.
🤖 Don't fully get this? Learn it with Claude
Stuck on Evaluate Boolean Expression? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **Evaluate Boolean Expression** (Databases) and want to truly understand it. Explain Evaluate Boolean Expression from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **Evaluate Boolean Expression** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **Evaluate Boolean Expression** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **Evaluate Boolean Expression** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.