How to fix Division by zero in PostgreSQL

PostgreSQLBEGINNERMEDIUMUpdated Dec 26, 2025· 190 views

PostgreSQL error 22012 occurs when an SQL query attempts to divide a numeric value by zero. This runtime error stops query execution and rolls back the transaction. Use NULLIF(), CASE statements, or data filtering to prevent this error.

Quick fix

Fixes 22012

-- Example queries that cause division by zero
SELECT user_id, total_sales / total_orders FROM user_stats;
-- ERROR: division by zero (when total_orders is 0)

SELECT profit / expenses FROM financial_reports;
-- ERROR: division by zero (when expenses is 0)

SELECT (a - b) / (c - d) FROM calculations;
-- ERROR: division by zero (when c equals d)
  1. Identify the problematic query
  2. Find rows with zero divisor values
  3. Use NULLIF() to convert zeros to NULL
  4. Add WHERE clause to filter zero divisors
postgresql — error
-- Example queries that cause division by zero
SELECT user_id, total_sales / total_orders FROM user_stats;
-- ERROR: division by zero (when total_orders is 0)
SELECT profit / expenses FROM financial_reports;
-- ERROR: division by zero (when expenses is 0)
SELECT (a - b) / (c - d) FROM calculations;
-- ERROR: division by zero (when c equals d)
Division by zero

What this error means

The PostgreSQL error code 22012 "division_by_zero" occurs when any numeric expression attempts to divide by zero, either a literal zero value or a column that evaluates to zero. This is a strict mathematical rule enforced by the database engine to prevent undefined calculations. When PostgreSQL encounters division by zero, it immediately stops query execution and raises an error with SQLSTATE 22012. This error cannot be suppressed with database settings—you must handle the condition in your SQL logic or application code. The error typically occurs during calculations, financial reports, rate computations, or analytics queries where denominator values aren't pre-validated. Unlike some databases that return NULL or Infinity for division by zero, PostgreSQL treats this as an error condition. NULL values divided by any number correctly return NULL, but dividing by NULL also returns NULL rather than an error—only literal or computed zeros trigger the 22012 error.

Typical symptoms

  • Query fails with error "ERROR: division by zero" and SQLSTATE 22012
  • Application crashes when executing financial or rate calculation queries
  • Reports or analytics queries abort unexpectedly on certain data subsets
  • Transaction rolls back when division by zero occurs
  • Error appears intermittently, only for specific data values
  • Calculations that should work with some rows fail unexpectedly

Common causes

  1. Dividing by a column value that contains zero for one or more rows
  2. Computing a divisor that evaluates to zero (e.g., (x - x), (y * 0))
  3. Rate calculations like (success_count / total_attempts) where total_attempts can be zero
  4. Financial calculations like (profit / expenses) where expenses may be zero
  5. Aggregate functions that return zero (e.g., COUNT(*) in HAVING clause)
  6. Subquery results that evaluate to zero used as denominators
  7. Using user-supplied values as divisors without validation

How to fix "Division by zero"

1Identify the problematic query

Find the query causing the division by zero error by examining your application logs or PostgreSQL error messages. Look for numeric division operations (/ operator) in your SELECT, WHERE, or calculated columns.

sql
-- Example queries that cause division by zero
SELECT user_id, total_sales / total_orders FROM user_stats;
-- ERROR: division by zero (when total_orders is 0)

SELECT profit / expenses FROM financial_reports;
-- ERROR: division by zero (when expenses is 0)

SELECT (a - b) / (c - d) FROM calculations;
-- ERROR: division by zero (when c equals d)

Use this template to find your problematic expression: SELECT ... / ... FROM ...

2Find rows with zero divisor values

Query your data to identify which rows have zero or null values in the denominator column. This shows the scope of the problem.

sql
-- Find rows where divisor is zero
SELECT id, total_orders, total_sales
FROM user_stats
WHERE total_orders = 0;

-- Count how many rows are affected
SELECT COUNT(*) as affected_rows
FROM financial_reports
WHERE expenses = 0 OR expenses IS NULL;

-- Check for derived zero values
SELECT id, (col_a - col_b) as divisor
FROM my_table
WHERE (col_a - col_b) = 0;

Understanding the extent of the issue helps you choose the best fix approach.

3Use NULLIF() to convert zeros to NULL

The simplest fix is to use NULLIF() to convert zero divisors to NULL. This prevents the error because dividing by NULL returns NULL (not an error). COALESCE() can provide a default value if needed.

sql
-- Basic NULLIF approach
SELECT
  user_id,
  total_sales / NULLIF(total_orders, 0) as avg_sale
FROM user_stats;

-- With COALESCE to provide a default
SELECT
  user_id,
  COALESCE(total_sales / NULLIF(total_orders, 0), 0) as avg_sale
FROM user_stats;

-- For multiple divisions
SELECT
  id,
  revenue / NULLIF(expenses, 0) as profit_ratio,
  profit / NULLIF(investment, 0) as roi
FROM financial_data;

This is the most concise solution and works well when NULL results are acceptable for zero divisors.

4Add WHERE clause to filter zero divisors

If you want to exclude rows with zero divisors entirely, add a WHERE clause to filter them before calculation. This approach ensures all results are valid numbers.

sql
-- Filter out zero divisors
SELECT
  user_id,
  total_sales / total_orders as avg_sale
FROM user_stats
WHERE total_orders > 0;

-- Multiple conditions
SELECT
  id,
  revenue / expenses as profit_margin
FROM financial_reports
WHERE expenses > 0
  AND revenue > 0
  AND report_year = 2024;

-- With aggregate functions
SELECT
  category,
  SUM(revenue) / SUM(expenses) as total_margin
FROM sales_data
WHERE expenses > 0
GROUP BY category;

This approach is clean and improves performance by reducing the result set size.

5Use CASE statement for conditional logic

For more complex scenarios, use CASE to implement custom logic for handling zero divisors. This gives you full control over edge cases.

sql
-- Return NULL for zero divisors
SELECT
  user_id,
  CASE
    WHEN total_orders > 0 THEN total_sales / total_orders
    ELSE NULL
  END as avg_sale
FROM user_stats;

-- Return a default value instead of NULL
SELECT
  id,
  CASE
    WHEN expenses > 0 THEN revenue / expenses
    ELSE 0  -- or any default value
  END as profit_margin
FROM financial_reports;

-- Multi-level logic
SELECT
  id,
  category,
  CASE
    WHEN divisor > 0 THEN numerator / divisor
    WHEN divisor = 0 THEN NULL
    ELSE -1  -- Flag error conditions
  END as result
FROM calculations;

CASE statements let you handle different conditions distinctly (zero, positive, negative).

6Use GREATEST() to ensure minimum value

The GREATEST() function returns the larger of two values. Use it to ensure the divisor never goes below a safe minimum (usually 1).

sql
-- Ensure divisor is at least 1
SELECT
  user_id,
  total_sales / GREATEST(total_orders, 1) as avg_sale
FROM user_stats;

-- With multiple columns
SELECT
  product_id,
  total_revenue / GREATEST(total_units, 1) as avg_price
FROM inventory;

-- In aggregate queries
SELECT
  category,
  SUM(amount) / GREATEST(COUNT(*), 1) as avg_amount
FROM transactions
GROUP BY category;

This ensures the divisor never reaches zero while preserving all rows in your result set.

7Validate data quality to prevent zeros

For long-term solutions, add constraints or validation logic to prevent zero values from entering the database in the first place.

sql
-- Add CHECK constraint to ensure positive values
ALTER TABLE user_stats
ADD CONSTRAINT chk_positive_orders
CHECK (total_orders >= 0);

-- Use DEFAULT values
ALTER TABLE financial_reports
ALTER COLUMN expenses SET DEFAULT 1;

-- Add NOT NULL constraints where zero shouldn't exist
ALTER TABLE calculations
ALTER COLUMN divisor SET NOT NULL;

-- Create index for filtered queries
CREATE INDEX idx_user_stats_active
ON user_stats (user_id)
WHERE total_orders > 0;

Prevention through data integrity constraints reduces the need for division by zero handling in queries.

Advanced notes

PostgreSQL Null Behavior in Division:

PostgreSQL handles NULL values differently from zero in division:
- value / NULL = NULL (no error)
- NULL / value = NULL (no error)
- value / 0 = ERROR 22012 (division by zero)

This is why NULLIF() is such an effective fix—converting zero to NULL leverages PostgreSQL's NULL handling.

Mathematical Functions and Division by Zero:

Some PostgreSQL functions handle division by zero in specific ways:
- MOD(x, 0) also raises error 22012
- % operator (modulo) raises error 22012
- Standard division (/) raises error 22012
- Integer division (/) raises error 22012

Performance Considerations:

When filtering large datasets, consider these optimizations:
1. Create indexes on commonly filtered columns (WHERE expense > 0)
2. Use materialized views for frequently calculated ratios
3. Pre-calculate ratios during ETL if the data is large

sql
-- Create materialized view to pre-calculate safe ratios
CREATE MATERIALIZED VIEW user_statistics AS
SELECT
  user_id,
  total_sales / GREATEST(total_orders, 1) as avg_sale,
  COUNT(*) as transaction_count
FROM user_stats
GROUP BY user_id;

Aggregate Functions and Division by Zero:

When using GROUP BY with division, ensure your group-level divisor is protected:

sql
-- Dangerous: SUM() could be 0
SELECT category, SUM(amount) / SUM(quantity) FROM sales GROUP BY category;

-- Safe: NULLIF protects aggregates
SELECT
  category,
  SUM(amount) / NULLIF(SUM(quantity), 0)
FROM sales
GROUP BY category;

Handling Derived Zero Divisors:

When the divisor is a calculated expression, the same rules apply:

sql
-- Derived zero: (a - a) = 0
SELECT value / NULLIF(a - a, 0) FROM table;

-- Practical example: percentage change where old = new
SELECT
  (new_value - old_value) / NULLIF(old_value, 0) as pct_change
FROM metrics;

Frequently asked questions

What does "22012" mean?
The PostgreSQL error code 22012 "division_by_zero" occurs when any numeric expression attempts to divide by zero, either a literal zero value or a column that evaluates to zero. This is a strict mathematical rule enforced by the database engine to prevent undefined calculations. When PostgreSQL encounters division by zero, it immediately stops query execution and raises an error with SQLSTATE 22012.
How do I fix "22012"?
PostgreSQL error 22012 occurs when an SQL query attempts to divide a numeric value by zero. This runtime error stops query execution and rolls back the transaction. Use NULLIF(), CASE statements, or data filtering to prevent this error.
What causes "22012"?
Dividing by a column value that contains zero for one or more rows Computing a divisor that evaluates to zero (e.g., (x - x), (y * 0)) Rate calculations like (success_count / total_attempts) where total_attempts can be zero
Is the "22012" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading