Loading content...
When querying databases, single conditions are rarely sufficient. Real-world data retrieval almost always requires multiple conditions that must all be true simultaneously. A human resources system doesn't just find employees—it finds active employees in the engineering department hired after 2020 with a salary above $80,000. An e-commerce platform doesn't just list products—it finds in-stock products in the electronics category priced between $100 and $500 with ratings above 4 stars.
The AND operator is the fundamental building block for expressing this kind of conjunctive logic in SQL. It allows you to specify that every condition in your query must evaluate to TRUE for a row to be included in the result set.
Understanding AND thoroughly—including its truth table semantics, behavior with NULL values, and performance characteristics—is essential for writing precise, efficient queries.
By the end of this page, you will master the AND operator completely: its formal semantics derived from Boolean algebra, its behavior in SQL's three-valued logic with NULLs, its practical applications for multi-condition filtering, and optimization strategies for AND-heavy queries.
The AND operator performs logical conjunction—a fundamental operation from Boolean algebra. In SQL, AND combines two or more conditions and returns TRUE only when all conditions are TRUE.
Formal Definition:
condition1 AND condition2 → TRUE if and only if:
- condition1 evaluates to TRUE, AND
- condition2 evaluates to TRUE
This definition extends naturally to any number of conditions:
condition1 AND condition2 AND condition3 AND ... AND conditionN → TRUE
if and only if ALL conditions evaluate to TRUE
12345678910111213141516171819
-- Basic AND SyntaxSELECT column1, column2, ...FROM table_nameWHERE condition1 AND condition2; -- Example: Find employees in Engineering department earning over $80,000SELECT employee_id, first_name, last_name, department, salaryFROM employeesWHERE department = 'Engineering' AND salary > 80000; -- Multiple AND conditionsSELECT product_id, name, price, stock_quantityFROM productsWHERE category = 'Electronics' AND price >= 100 AND price <= 500 AND stock_quantity > 0 AND rating >= 4.0;When chaining multiple AND conditions, place each condition on a new line with AND at the beginning. This improves readability and makes it easy to add, remove, or comment out individual conditions during development and debugging.
Understanding AND requires internalizing its truth table—the complete specification of how AND evaluates based on its operands.
Binary Truth Table (Classical Logic):
In classical Boolean algebra with only TRUE and FALSE values:
| Condition A | Condition B | A AND B |
|---|---|---|
| TRUE | TRUE | TRUE |
| TRUE | FALSE | FALSE |
| FALSE | TRUE | FALSE |
| FALSE | FALSE | FALSE |
Key Insight: AND is the most restrictive logical operator. Only one combination—both operands TRUE—produces a TRUE result. Every other combination yields FALSE.
This property has profound implications:
Truth tables aren't just theoretical—they help you predict query behavior. If you have 1,000 rows, a single condition might match 200 rows. Adding an AND condition can only further reduce this (matching perhaps 50 rows). Understanding this helps you structure efficient queries and anticipate result sizes.
SQL extends classical two-valued Boolean logic with a third value: UNKNOWN, which arises when expressions involve NULL. This creates three-valued logic (3VL), which profoundly affects how AND behaves.
Why NULL Creates UNKNOWN:
NULL represents an unknown, missing, or inapplicable value. When you compare something to NULL, the result isn't TRUE or FALSE—it's UNKNOWN because we cannot determine the truth without knowing the actual value.
-- This expression evaluates to UNKNOWN, not TRUE or FALSE
NULL = 5 → UNKNOWN
NULL > 10 → UNKNOWN
NULL = NULL → UNKNOWN
| Condition A | Condition B | A AND B | Explanation |
|---|---|---|---|
| TRUE | TRUE | TRUE | Both known to be true |
| TRUE | UNKNOWN | UNKNOWN | Can't determine—depends on unknown value |
| TRUE | FALSE | FALSE | One false is sufficient |
| UNKNOWN | TRUE | UNKNOWN | Can't determine—depends on unknown value |
| UNKNOWN | UNKNOWN | UNKNOWN | Both values unknown |
| UNKNOWN | FALSE | FALSE | One false is sufficient |
| FALSE | TRUE | FALSE | One false is sufficient |
| FALSE | UNKNOWN | FALSE | One false is sufficient |
| FALSE | FALSE | FALSE | Both false |
Critical Rule: FALSE AND UNKNOWN = FALSE
This makes logical sense: if we know one condition is FALSE, the conjunction must be FALSE regardless of the other value. AND requires all conditions to be TRUE, so a single FALSE is decisive.
But: TRUE AND UNKNOWN = UNKNOWN
This is trickier: we know one condition is TRUE, but the other is unknown. The conjunction might be TRUE (if the unknown value is TRUE) or FALSE (if it's FALSE). We simply can't tell.
12345678910111213141516171819202122
-- Table: employees-- | emp_id | name | department | commission |-- |--------|---------|------------|------------|-- | 1 | Alice | Sales | 5000 |-- | 2 | Bob | Sales | NULL | -- Commission unknown-- | 3 | Charlie | Engineering| NULL | -- No commission (N/A)-- | 4 | Diana | Sales | 3000 | -- Query: Find Sales employees with commission > 2000SELECT emp_id, name, commissionFROM employeesWHERE department = 'Sales' AND commission > 2000; -- Analysis:-- Alice: 'Sales' = 'Sales' → TRUE AND 5000 > 2000 → TRUE = TRUE ✓-- Bob: 'Sales' = 'Sales' → TRUE AND NULL > 2000 → UNKNOWN = UNKNOWN (excluded)-- Charlie: 'Engineering' = 'Sales' → FALSE AND ... = FALSE (excluded)-- Diana: 'Sales' = 'Sales' → TRUE AND 3000 > 2000 → TRUE = TRUE ✓ -- Result: Only Alice and Diana returned-- Bob is EXCLUDED because TRUE AND UNKNOWN = UNKNOWN, not TRUERows with NULL values in columns used in AND conditions are typically excluded from results unless explicitly handled. This is a common source of bugs—developers expect rows with NULL to appear when they match other conditions, but UNKNOWN results in exclusion. Always consider: 'What if this column is NULL?'
Many programming languages implement short-circuit evaluation for AND: if the first operand is FALSE, the second operand is never evaluated because the result is already determined.
Does SQL short-circuit AND?
The SQL standard does not mandate short-circuit evaluation, and behavior varies across database systems:
Why This Matters:
If you write a query assuming left-to-right short-circuit evaluation, you might be surprised when a database evaluates conditions in a different order—potentially causing errors or unexpected behavior.
1234567891011121314151617181920212223242526
-- Dangerous assumption: relying on short-circuit evaluation-- Suppose 'value' column sometimes contains non-numeric strings -- WRONG: Assumes left-to-right short-circuitSELECT *FROM mixed_dataWHERE is_numeric = TRUE AND CAST(value AS INTEGER) > 100; -- If the database evaluates CAST() first (before checking is_numeric),-- this query will ERROR on non-numeric values! -- SAFER: Use CASE to guarantee evaluation orderSELECT *FROM mixed_dataWHERE CASE WHEN is_numeric = TRUE THEN CAST(value AS INTEGER) > 100 ELSE FALSE END; -- BEST: Separate with a CTE or subqueryWITH numeric_only AS ( SELECT * FROM mixed_data WHERE is_numeric = TRUE)SELECT * FROM numeric_onlyWHERE CAST(value AS INTEGER) > 100;Database optimizers may reorder AND conditions for performance. A condition you placed 'first' for safety might be evaluated last. If one condition guards against errors in another, use CASE expressions or CTEs to guarantee evaluation order.
AND enables sophisticated data filtering that mirrors real-world business requirements. Let's examine common patterns:
Range queries require both lower and upper bounds, naturally using AND:
1234567891011121314151617181920
-- Price rangeSELECT product_name, priceFROM productsWHERE price >= 50.00 AND price <= 200.00; -- Equivalent using BETWEEN (which is AND under the hood)SELECT product_name, priceFROM productsWHERE price BETWEEN 50.00 AND 200.00; -- Date range with explicit ANDSELECT order_id, order_date, totalFROM ordersWHERE order_date >= '2024-01-01' AND order_date < '2024-04-01'; -- Age range for eligibilitySELECT applicant_id, name, ageFROM applicantsWHERE age >= 21 AND age <= 65;AND conditions directly impact query performance. Understanding how databases process AND helps you write efficient queries:
123456789101112131415161718
-- Scenario: Frequent query patternSELECT * FROM ordersWHERE customer_id = 12345 AND order_date >= '2024-01-01' AND status = 'Shipped'; -- Optimal: Create a composite index matching AND conditionsCREATE INDEX idx_orders_customer_date_status ON orders(customer_id, order_date, status); -- This index enables efficient lookup:-- 1. Seek directly to customer_id = 12345-- 2. Within those, range scan order_date >= '2024-01-01'-- 3. Filter by status = 'Shipped' -- Index column order matters!-- Place equality conditions (=) before range conditions (>=, <=, BETWEEN)-- Because range conditions "consume" the remaining indexWhen designing indexes for queries with multiple AND conditions, include columns in order of: (1) equality conditions first, (2) range conditions second, (3) most selective conditions earlier. This maximizes index efficiency by allowing the database to seek rather than scan.
Even experienced developers make these AND-related errors:
WHERE status = 'Active' AND status = 'Pending' which can never be true1234567891011121314151617181920212223
-- MISTAKE 1: Impossible conditionSELECT * FROM productsWHERE category = 'Electronics' AND category = 'Clothing';-- This returns NOTHING! A product can't be in two categories simultaneously. -- MISTAKE 2: Forgetting NULLSELECT * FROM employeesWHERE department = 'Sales' AND bonus > 0;-- Employees with NULL bonus are excluded! If you want them, use:SELECT * FROM employeesWHERE department = 'Sales' AND (bonus > 0 OR bonus IS NULL); -- MISTAKE 3: Redundant conditionsSELECT * FROM productsWHERE price > 100 AND price > 50;-- The second condition is redundant—if price > 100, it's already > 50 -- MISTAKE 4: Precedence confusion (covered in depth in later pages)SELECT * FROM employeesWHERE department = 'Sales' OR department = 'Marketing' AND salary > 50000;-- This is actually: Sales OR (Marketing AND salary > 50000)-- NOT: (Sales OR Marketing) AND salary > 50000The AND operator is deceptively simple but forms the backbone of precise data querying. Let's consolidate the key insights:
What's Next:
The AND operator enables precise conjunction, but many queries require specifying alternative conditions—'either this OR that.' The next page explores the OR operator, which provides disjunction: matching rows that satisfy any of the specified conditions.
You now understand the AND operator comprehensively—from its Boolean algebra foundations through SQL's three-valued logic to practical performance optimization. Next, we'll explore OR, which opens up query possibilities by allowing alternative matching conditions.