---
title: "HAVING clause"
description: "The HAVING clause filters grouped results after aggregation, letting you keep or discard groups based on conditions over aggregate values like SUM() or COUNT()."
canonical: "https://motherduck.com/glossary/having-clause/"
related:
  - title: "Aggregate functions | MotherDuck Docs"
    url: "https://motherduck.com/docs/sql-reference/duckdb-sql-reference/aggregate-functions/"
  - title: "Don't Fear the Agents - AI on the Data Lakehouse"
    url: "https://motherduck.com/blog/dont-fear-the-agents-ai-on-the-data-lakehouse/"
  - title: "Query syntax | MotherDuck Docs"
    url: "https://motherduck.com/docs/sql-reference/duckdb-sql-reference/query-syntax/"
---

# HAVING clause

> The HAVING clause filters grouped results after aggregation, letting you keep or discard groups based on conditions over aggregate values like SUM() or COUNT().

## Overview
`HAVING` filters the output of a `GROUP BY` clause. While `WHERE` filters individual rows before grouping, `HAVING` filters entire groups after their aggregate values (`SUM`, `COUNT`, `AVG`, etc.) have been computed. It exists specifically to let you write conditions like "only show customers whose total spend exceeds $1,000" -- something `WHERE` cannot express because the aggregate doesn't exist yet at the row level.

<glossary-callout guide="duckdb-cheatsheet-full" />

## Syntax and example
```sql
SELECT customer_id, SUM(order_total) AS total_spent, COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
HAVING SUM(order_total) > 1000
   AND COUNT(*) >= 3;
```

Here, `WHERE` could still be added to the same query to pre-filter rows (e.g., `WHERE status = 'completed'`) before grouping, while `HAVING` filters the resulting groups.

## HAVING without GROUP BY
`HAVING` can technically appear without an explicit `GROUP BY`; in that case the entire result set is treated as a single group:

```sql
SELECT SUM(order_total) AS total_revenue
FROM orders
HAVING SUM(order_total) > 1000000;
```

## DuckDB notes
DuckDB's "friendly SQL" extensions let `HAVING` reference an aggregate alias defined in the `SELECT` list directly, instead of repeating the full aggregate expression:

```sql
SELECT customer_id, SUM(order_total) AS total_spent
FROM orders
GROUP BY customer_id
HAVING total_spent > 1000;
```

This works because DuckDB resolves non-aggregate aliases in `WHERE`/`GROUP BY` and aggregate aliases in `HAVING`, within the same query, avoiding an extra subquery or CTE that other databases often require.

## Evaluation order
Query clauses execute logically as `FROM` -> `WHERE` -> `GROUP BY` -> `HAVING` -> `SELECT` -> `ORDER BY` -> `LIMIT`, which is why `HAVING` can reference aggregates but `WHERE` cannot.