sqlcmd.net validated sql reference
intermediate grouping MySQL MariaDB SQL Server PostgreSQL SQLite

Use WHERE Before GROUP BY And HAVING After

`WHERE` filters individual rows before grouping. `HAVING` filters grouped results after aggregates are computed.

Docker-validated Not currently validation-green

Filter grouped customers after counting orders

WHERE status = 'paid' removes Carol's cancelled row before grouping starts. The grouped result then contains Alice with 2 paid orders and Bob with 1. HAVING COUNT(*) > 1 runs after grouping and keeps only Alice.

Rows loaded before the example query runs.
Setup
CREATE TABLE orders (
  id INT,
  customer_name VARCHAR(50),
  status VARCHAR(20)
);

INSERT INTO
  orders (id, customer_name, status)
VALUES
  (1, 'Alice', 'paid'),
  (2, 'Alice', 'paid'),
  (3, 'Bob', 'paid'),
  (4, 'Carol', 'cancelled');
Shared across supported engines.
SQL
SELECT
  customer_name,
  COUNT(*) AS paid_orders
FROM
  orders
WHERE
  status = 'paid'
GROUP BY
  customer_name
HAVING
  COUNT(*) > 1
ORDER BY
  customer_name;
Returned rows for the shared example.
customer_namepaid_orders
Alice2

`WHERE` reduces the input rows first, then `HAVING` filters the grouped totals.

Where this command helps.

  • filtering grouped reports by aggregate thresholds
  • separating row-level filters from post-aggregation filters

What the command is doing.

A common reporting bug is trying to use WHERE with aggregate conditions such as COUNT(*) > 1. That does not match SQL's execution order. WHERE runs before grouping, so it filters source rows. HAVING runs after GROUP BY, so it filters the grouped output and can reference aggregates safely.