Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How is HAVING different from WHERE when filtering grouped results?

Quick answer

Use WHERE to remove individual rows before the database forms groups. Use HAVING to keep or discard groups after grouping, often by testing an aggregate such as SUM. For example, WHERE amount > 0 excludes nonpositive transactions before totals are calculated, while HAVING SUM(amount) >= 100 keeps only groups whose resulting total is at least 100. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I’m grouping sales by salesperson and want to show only positive transactions, then keep only people whose total is at least 100. Which condition goes where?

Geez

Put the transaction-level condition in WHERE and the group-total condition in HAVING. In this example, WHERE amount > 0 removes any row with a zero or negative amount before it contributes to a salesperson’s total. Then GROUP BY forms one group per salesperson, and HAVING SUM(amount) >= 100 keeps only groups whose calculated total meets the threshold. [S1]

A simple SELECT applies WHERE before grouping and HAVING after groups are formed. [S1] The short version is: WHERE asks, “Does this row qualify?” HAVING asks, “Does this group qualify?”

Follow-up question

Can you show the difference with small sample data and the actual result?

Geez

Assume these invented sales rows; the names and amounts are just an example:

  • Ana: 40
  • Ana: -10
  • Ana: 80
  • Bo: 60
  • Bo: 50
  • Cy: -20
  • Cy: 150

With WHERE amount > 0, Ana’s -10 and Cy’s -20 are excluded before totals are formed. The remaining totals are Ana 120, Bo 110, and Cy 150. Applying HAVING SUM(amount) >= 115 leaves Ana and Cy; Bo’s 110 does not meet the threshold.

Here is the paired query:

SELECT salesperson, SUM(amount) AS total_amount
FROM sales
WHERE amount > 0
GROUP BY salesperson
HAVING SUM(amount) >= 115;

The result is Ana — 120 and Cy — 150. The WHERE condition changes which transactions contribute to each total; the HAVING condition decides which completed totals appear. This follows the described SQLite SELECT behavior. [S1]

Follow-up question

What if I remove WHERE or move the positive-amount test to HAVING?

Geez

If you remove WHERE but leave HAVING SUM(amount) >= 115, the negative rows still contribute to their groups: Ana totals 110, Bo 110, and Cy 130. Only Cy then meets 115. That is a different calculation, not merely a different way to express the same filter.

A condition such as amount > 0 describes individual transaction rows, so it belongs in WHERE when you want to exclude those rows before totals are calculated. HAVING is for a condition evaluated on each completed group, commonly using an aggregate such as SUM. [S1] Avoid moving a row-level test to HAVING when doing so would change which records contribute to the aggregate.

Follow-up question

Can you give me a reusable pattern and a quick way to check my query?

Geez

Use this shape, replacing the bracketed names and conditions with yours:

SELECT [group_column], [aggregate_function]([value_column]) AS [summary]
FROM [table_name]
WHERE [row_condition]
GROUP BY [group_column]
HAVING [aggregate_function]([value_column]) [comparison] [threshold];

For the sales example, the row condition is amount > 0, the grouping column is salesperson, and the group condition is SUM(amount) >= 115. Check each condition by asking what it refers to: one source row, or a group summary? Then hand-calculate one small group to confirm which rows contribute and whether its final total passes HAVING.

The example demonstrates SQLite’s stated SELECT semantics; it does not establish behavior for every database system or every query feature. If you use another database, check its documentation for details specific to your query. [S1]

A practical checklist

  • Write down which individual rows should contribute to the calculation.

  • Put row-level filters in WHERE when they should be applied before grouping.

  • Choose the grouping column or columns in GROUP BY.

  • Put conditions on group summaries, such as SUM(amount), in HAVING.

  • Test the query with a few hand-calculated rows, including a row that WHERE excludes and a group that HAVING rejects.

A few more useful answers

Does WHERE filter groups?

WHERE filters input rows before groups are formed. To keep or discard completed groups based on an aggregate, use HAVING. [S1]

Can a query use both WHERE and HAVING?

Yes. Use WHERE to select contributing rows and HAVING to filter the resulting groups, as in the sales example. [S1]

Does HAVING always need an aggregate?

The example and cited SQLite guidance show HAVING evaluated for each group, with aggregates evaluated across that group. They do not establish rules for every database or every kind of HAVING expression, so check the documentation for your database when using other forms. [S1]

Sources

References used for this guide.

  1. [S1] SQLite SELECT: WHERE, GROUP BY, and HAVING processing
    sqlite.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work