PostgreSQL AND Operator

Learn how the PostgreSQL AND operator combines boolean expressions in WHERE clauses, its three-valued logic truth table, and performance implications for multi-condition queries.

5 min read · Back to overview

Quick Answer

The AND operator returns TRUE only when both expressions are TRUE. It returns FALSE if either expression is FALSE, and NULL when one side is NULL and the other is TRUE. Use AND in WHERE clauses to require that every condition is satisfied simultaneously.

Spin up a Postgres database in 20 seconds with Vela.

Try Vela Sandbox

The AND operator is a logical operator in PostgreSQL that combines two Boolean expressions and requires both to be TRUE for the combined expression to return TRUE. It is most commonly used in WHERE clauses to narrow a result set by applying multiple conditions simultaneously.

Syntax

expression1 AND expression2

PostgreSQL boolean logic is three-valued: TRUE, FALSE, and NULL. The full truth table for AND:

LeftRightResult
TRUETRUETRUE
TRUEFALSEFALSE
TRUENULLNULL
FALSEFALSEFALSE
FALSENULLFALSE
NULLNULLNULL

The key rule: AND returns TRUE only when both operands are TRUE. If either side is definitively FALSE, the result is FALSE regardless of the other side.

Practical Example

Create a sample table for a product inventory system:

CREATE TABLE products (
  product_id   SERIAL PRIMARY KEY,
  name         VARCHAR(100) NOT NULL,
  category     VARCHAR(50)  NOT NULL,
  unit_price   NUMERIC(10,2) NOT NULL,
  stock_qty    INT           NOT NULL DEFAULT 0,
  is_active    BOOLEAN       NOT NULL DEFAULT TRUE
);

INSERT INTO products (name, category, unit_price, stock_qty, is_active) VALUES
  ('Wireless Headset',   'Electronics', 89.99,  45, TRUE),
  ('Standing Desk',      'Furniture',   349.00, 12, TRUE),
  ('USB-C Hub',          'Electronics', 39.99,   0, TRUE),
  ('Office Chair',       'Furniture',   220.00,  8, FALSE),
  ('Mechanical Keyboard','Electronics', 129.00, 20, TRUE);

Find active electronics products with stock available:

SELECT name, unit_price, stock_qty
FROM products
WHERE category = 'Electronics'
  AND is_active = TRUE
  AND stock_qty > 0
ORDER BY unit_price;

Expected result:

        name         | unit_price | stock_qty
---------------------+------------+-----------
 USB-C Hub           |      39.99 |         0
 Wireless Headset    |      89.99 |        45
 Mechanical Keyboard |     129.00 |        20

Wait — USB-C Hub has stock_qty = 0, so it should be excluded. Verify by tightening the condition:

SELECT name, unit_price, stock_qty
FROM products
WHERE category = 'Electronics'
  AND is_active = TRUE
  AND stock_qty > 0
ORDER BY unit_price;
        name         | unit_price | stock_qty
---------------------+------------+-----------
 Wireless Headset    |      89.99 |        45
 Mechanical Keyboard |     129.00 |        20

Inspect the index usage with EXPLAIN ANALYZE:

EXPLAIN ANALYZE
SELECT name, unit_price
FROM products
WHERE category = 'Electronics'
  AND is_active = TRUE
  AND stock_qty > 0;

AND Precedence and Parentheses

AND has higher precedence than OR. Without parentheses, mixed expressions may behave unexpectedly:

-- Evaluated as: (category = 'Electronics' AND stock_qty > 0) OR is_active = FALSE
WHERE category = 'Electronics' AND stock_qty > 0 OR is_active = FALSE;

-- Explicit grouping — require stock_qty > 0 for both cases:
WHERE (category = 'Electronics' OR is_active = FALSE) AND stock_qty > 0;

Always use parentheses when combining AND and OR to make your intent unambiguous.

NULL Behavior

Because any comparison with NULL produces NULL, filtering with AND against nullable columns requires care:

-- This always returns NULL (never TRUE) — use IS NULL instead
WHERE discontinued_at = NULL AND category = 'Electronics';  -- wrong

-- Correct approach
WHERE discontinued_at IS NULL AND category = 'Electronics';

Testing with Vela

Queries with multiple AND conditions can silently return fewer rows than expected if any condition unintentionally eliminates valid rows. Use Vela’s database branching to test complex WHERE predicates against a production-scale data copy before running UPDATE or DELETE statements. Create a branch, run the query as a SELECT to inspect the row count, then promote to production only when the result set is correct.

Production Tips

  • Use parentheses liberally when combining AND and ORAND binds tighter and can produce subtle logic bugs without them.
  • PostgreSQL can use a BitmapAnd plan to combine separate indexes when multiple AND conditions each have their own index. A composite index on all AND columns in the correct order often performs better than separate single-column indexes.
  • Avoid NOT IN combined with AND when the subquery might return NULL — this causes zero rows to be returned. Use NOT EXISTS instead.
  • Test selective filter combinations with EXPLAIN ANALYZE to confirm the planner’s row estimates match reality.
  • Wrap UPDATE and DELETE statements that use AND filters in a BEGIN/COMMIT block so you can ROLLBACK if the predicate is wrong.

Continue in Filtering Data: OR Operator.

Related in this section: PostgreSQL WHERE · OR Operator · LIMIT

Frequently Asked Questions

What does AND return when one expression is NULL?
TRUE AND NULL returns NULL because the outcome is uncertain. FALSE AND NULL returns FALSE because even if the unknown side were TRUE the overall result would still be FALSE. NULL AND NULL returns NULL. Only TRUE AND TRUE produces TRUE.
Does the AND operator lock the table in PostgreSQL?
No. AND is a logical operator evaluated at query execution time. It does not acquire any locks. Only data-modification statements (UPDATE, DELETE, INSERT) and DDL commands acquire locks on tables.
What happens to dependent objects when I use AND with subqueries?
AND is a predicate operator, not a DDL command, so it has no effect on dependent objects. When AND combines conditions that reference columns covered by indexes, PostgreSQL may use a BitmapAnd plan to intersect index scans, but the underlying table structure is unchanged.
Can I chain more than two conditions with AND?
Yes. You can chain as many conditions as needed: WHERE status = 'active' AND region = 'EU' AND amount > 100 AND created_at >= '2026-01-01'. All conditions must evaluate to TRUE for a row to be included in the result.
What is the safest way to use AND with multiple conditions in production?
Always use parentheses when mixing AND and OR to make precedence explicit. AND has higher precedence than OR, so WHERE a AND b OR c is evaluated as WHERE (a AND b) OR c, which may differ from your intent. Test complex multi-condition filters on a branch database before executing against production data.