Bird
Raised Fist0
PostgreSQLquery~15 mins

FILTER clause for conditional aggregation in PostgreSQL - Deep Dive

Choose your learning style10 modes available
Overview - FILTER clause for conditional aggregation
What is it?
The FILTER clause in SQL lets you apply a condition inside an aggregate function. It means you can count, sum, or average only the rows that meet a specific condition, without needing extra queries or complicated tricks. This makes your queries simpler and clearer when you want to aggregate data based on some criteria.
Why it matters
Without the FILTER clause, you would have to write multiple queries or use complex CASE statements inside aggregates to get conditional results. This makes queries harder to read and slower to write. FILTER helps you get precise answers quickly, which is important when analyzing data or making decisions based on specific conditions.
Where it fits
Before learning FILTER, you should understand basic SQL SELECT statements, aggregate functions like COUNT and SUM, and simple WHERE clauses. After mastering FILTER, you can explore advanced SQL topics like window functions, grouping sets, and complex data analysis.
Mental Model
Core Idea
FILTER lets you tell an aggregate function exactly which rows to include by adding a condition right inside it.
Think of it like...
Imagine you have a basket of fruits and want to count only the apples. Instead of sorting the basket first, you just say 'count only if it’s an apple' while counting. FILTER is like that instruction inside the counting process.
Aggregate Function with FILTER:

  AGG_FUNC(column) FILTER (WHERE condition)

Example:
  COUNT(*) FILTER (WHERE status = 'active')

This counts only rows where status is 'active'.
Build-Up - 7 Steps
1
FoundationUnderstanding Basic Aggregates
πŸ€”
Concept: Learn what aggregate functions do in SQL.
Aggregate functions like COUNT, SUM, AVG, MIN, and MAX combine multiple rows into a single value. For example, COUNT(*) counts all rows, SUM(amount) adds up all amounts.
Result
You get a single number summarizing many rows.
Knowing aggregates is essential because FILTER modifies how these functions pick rows to include.
2
FoundationUsing WHERE Clause in Queries
πŸ€”
Concept: Learn how WHERE filters rows before aggregation.
The WHERE clause limits which rows the whole query sees. For example, SELECT COUNT(*) FROM sales WHERE region = 'East'; counts only sales in the East region.
Result
The aggregate works on a smaller set of rows filtered by WHERE.
WHERE filters rows before aggregation, but FILTER filters rows inside the aggregate itself.
3
IntermediateConditional Aggregation with CASE
πŸ€”Before reading on: do you think CASE inside aggregates is easy to read and write? Commit to your answer.
Concept: Use CASE inside aggregates to count or sum conditionally.
You can write COUNT(CASE WHEN condition THEN 1 END) to count only rows meeting the condition. For example, COUNT(CASE WHEN status = 'active' THEN 1 END) counts active rows.
Result
You get conditional counts or sums, but the syntax can be long and hard to read.
CASE works but can make queries complex and error-prone when conditions grow.
4
IntermediateIntroducing FILTER Clause Syntax
πŸ€”Before reading on: do you think FILTER can replace CASE inside aggregates? Commit to your answer.
Concept: FILTER clause adds a clear condition inside aggregate functions.
Instead of CASE, write COUNT(*) FILTER (WHERE status = 'active') to count only active rows. This is shorter and clearer.
Result
Queries become easier to read and write for conditional aggregation.
FILTER improves clarity and reduces mistakes compared to CASE inside aggregates.
5
IntermediateMultiple FILTER Clauses in One Query
πŸ€”
Concept: Use several FILTER clauses to get different conditional aggregates in one query.
You can write SELECT COUNT(*) FILTER (WHERE status = 'active') AS active_count, COUNT(*) FILTER (WHERE status = 'inactive') AS inactive_count FROM users; This counts active and inactive users separately in one query.
Result
You get multiple conditional aggregates side by side efficiently.
FILTER lets you combine many conditional counts or sums without repeating the whole query.
6
AdvancedFILTER with GROUP BY for Complex Analysis
πŸ€”Before reading on: do you think FILTER works differently with GROUP BY? Commit to your answer.
Concept: FILTER works inside grouped queries to conditionally aggregate per group.
Example: SELECT department, COUNT(*) AS total_employees, COUNT(*) FILTER (WHERE status = 'active') AS active_employees FROM employees GROUP BY department; This counts total and active employees per department.
Result
You get conditional aggregates calculated separately for each group.
FILTER integrates smoothly with GROUP BY, enabling detailed group-level conditional summaries.
7
ExpertPerformance and Optimization with FILTER
πŸ€”Before reading on: do you think FILTER always improves query speed? Commit to your answer.
Concept: FILTER can improve readability but may affect performance depending on indexes and query plans.
FILTER pushes conditions inside aggregates, which can help the database optimize aggregation. However, if conditions are complex or indexes missing, performance may not improve. Understanding query plans helps decide when to use FILTER.
Result
FILTER can make queries faster or slower depending on context.
Knowing how FILTER affects execution helps write both clear and efficient queries.
Under the Hood
FILTER works by applying the WHERE condition inside the aggregate function during query execution. Instead of filtering rows before aggregation, it tells the database engine to include only rows meeting the condition in that specific aggregate calculation. This allows multiple aggregates with different filters to run in one pass over the data.
Why designed this way?
FILTER was introduced to simplify conditional aggregation, replacing verbose CASE expressions. It was designed to improve query readability and maintainability while allowing the database optimizer to handle conditions efficiently inside aggregates. Alternatives like CASE were error-prone and harder to optimize.
Query Execution Flow with FILTER:

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Table Scan   β”‚
  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚ Rows
         β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ Aggregate Stepβ”‚
  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
  β”‚ β”‚ FILTER    β”‚ β”‚
  β”‚ β”‚ Condition β”‚ β”‚
  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚ Aggregated Result
         β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Final Output β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Myth Busters - 4 Common Misconceptions
Quick: Does FILTER apply its condition before or after grouping? Commit to your answer.
Common Belief:FILTER filters rows before grouping, just like WHERE.
Tap to reveal reality
Reality:FILTER applies conditions inside aggregate functions after grouping, unlike WHERE which filters rows before grouping.
Why it matters:Confusing FILTER with WHERE can lead to wrong query results, especially in grouped queries.
Quick: Can you use FILTER with non-aggregate functions? Commit to your answer.
Common Belief:FILTER can be used with any function, aggregate or not.
Tap to reveal reality
Reality:FILTER only works with aggregate functions; using it elsewhere causes errors.
Why it matters:Trying to use FILTER incorrectly leads to syntax errors and wasted debugging time.
Quick: Does FILTER always make queries faster? Commit to your answer.
Common Belief:FILTER always improves query performance.
Tap to reveal reality
Reality:FILTER improves readability but may not always improve performance; it depends on data, indexes, and query plans.
Why it matters:Assuming FILTER always speeds up queries can cause unexpected slowdowns in production.
Quick: Is FILTER a PostgreSQL-only feature? Commit to your answer.
Common Belief:FILTER is available in all SQL databases.
Tap to reveal reality
Reality:FILTER is part of the SQL standard but not supported by all databases; PostgreSQL supports it fully.
Why it matters:Using FILTER in unsupported databases causes errors; knowing compatibility avoids deployment issues.
Expert Zone
1
FILTER conditions can reference columns from the same table but cannot use aggregates inside the FILTER condition itself.
2
When combining FILTER with DISTINCT inside aggregates, the behavior can be subtle and requires careful testing.
3
FILTER clauses can be combined with window functions, but their interaction is complex and requires understanding of execution order.
When NOT to use
Avoid FILTER when working with databases that do not support it, or when conditions are too complex and better handled by pre-filtering or subqueries. Use CASE inside aggregates as a fallback. For very large datasets, test performance carefully before using FILTER.
Production Patterns
In production, FILTER is often used to produce multiple conditional aggregates in one query for dashboards and reports. It reduces query complexity and improves maintainability. It is also used with GROUP BY to segment data by categories with different conditions efficiently.
Connections
CASE expressions in SQL
FILTER is a cleaner alternative to CASE inside aggregates.
Understanding FILTER clarifies why CASE inside aggregates is verbose and how SQL evolved to simplify conditional aggregation.
Window functions
FILTER can be combined with window functions for advanced analytics.
Knowing FILTER helps grasp how conditions can be applied selectively in complex analytic queries.
Set theory in mathematics
FILTER acts like selecting subsets before aggregation, similar to filtering sets before applying operations.
Recognizing FILTER as subset selection deepens understanding of how data is grouped and summarized.
Common Pitfalls
#1Using WHERE instead of FILTER for conditional aggregation inside aggregates.
Wrong approach:SELECT COUNT(*) FROM sales WHERE status = 'active'; -- counts only active rows overall
Correct approach:SELECT COUNT(*) FILTER (WHERE status = 'active') FROM sales; -- counts active rows inside aggregate
Root cause:Confusing WHERE filtering of rows before aggregation with FILTER filtering inside aggregates.
#2Trying to use FILTER with non-aggregate functions.
Wrong approach:SELECT name FILTER (WHERE status = 'active') FROM users;
Correct approach:SELECT COUNT(name) FILTER (WHERE status = 'active') FROM users;
Root cause:Misunderstanding that FILTER only works with aggregate functions.
#3Writing FILTER without parentheses around WHERE condition.
Wrong approach:SELECT COUNT(*) FILTER WHERE status = 'active' FROM sales;
Correct approach:SELECT COUNT(*) FILTER (WHERE status = 'active') FROM sales;
Root cause:Syntax error due to missing parentheses around the WHERE clause in FILTER.
Key Takeaways
The FILTER clause lets you apply conditions inside aggregate functions to count or sum only certain rows.
FILTER improves query readability and reduces the need for complex CASE expressions in conditional aggregation.
FILTER applies conditions after grouping, unlike WHERE which filters rows before aggregation.
FILTER only works with aggregate functions and requires parentheses around the WHERE condition.
Understanding FILTER helps write clearer, more maintainable SQL queries for data analysis and reporting.

Practice

(1/5)
1. What does the FILTER clause do in a PostgreSQL aggregate function?
easy
A. It filters the entire table before aggregation starts.
B. It applies a condition to include only certain rows in the aggregation.
C. It changes the grouping columns in the query.
D. It sorts the results after aggregation.

Solution

  1. Step 1: Understand the purpose of FILTER in aggregation

    The FILTER clause allows you to specify a condition inside an aggregate function to include only rows that meet that condition.
  2. Step 2: Compare with other options

    FILTER does not filter the whole table before aggregation, nor does it change grouping or sort results. It only limits rows counted or summed inside the aggregate.
  3. Final Answer:

    It applies a condition to include only certain rows in the aggregation. -> Option B
  4. Quick Check:

    FILTER = condition inside aggregate [OK]
Hint: FILTER applies conditions inside aggregates, not on whole table [OK]
Common Mistakes:
  • Thinking FILTER filters rows before aggregation
  • Confusing FILTER with WHERE clause
  • Assuming FILTER changes GROUP BY columns
2. Which of the following is the correct syntax to count only rows where status = 'active' using FILTER in PostgreSQL?
easy
A. SELECT COUNT(*) FILTER (WHERE status = 'active') FROM users;
B. SELECT COUNT(*) FROM users FILTER (WHERE status = 'active');
C. SELECT COUNT(*) WHERE FILTER status = 'active' FROM users;
D. SELECT COUNT(*) FILTER WHERE status = 'active' FROM users;

Solution

  1. Step 1: Recall FILTER syntax in aggregate functions

    The correct syntax places FILTER with parentheses and a WHERE clause inside the aggregate function: COUNT(*) FILTER (WHERE condition).
  2. Step 2: Check each option

    SELECT COUNT(*) FILTER (WHERE status = 'active') FROM users; matches the correct syntax. The other options misuse FILTER placement or syntax.
  3. Final Answer:

    SELECT COUNT(*) FILTER (WHERE status = 'active') FROM users; -> Option A
  4. Quick Check:

    FILTER syntax = FILTER (WHERE condition) [OK]
Hint: Use FILTER (WHERE condition) inside aggregate parentheses [OK]
Common Mistakes:
  • Omitting parentheses after FILTER
  • Placing FILTER outside aggregate function
  • Using FILTER without WHERE keyword
3. Given the table sales with columns region and amount, what will this query return?
SELECT region, SUM(amount) FILTER (WHERE amount > 100) AS big_sales FROM sales GROUP BY region;
medium
A. Sum of all sales amounts per region.
B. Count of sales with amount greater than 100 per region.
C. Sum of sales amounts less than or equal to 100 per region.
D. Sum of sales amounts greater than 100 per region.

Solution

  1. Step 1: Understand the FILTER condition in SUM

    The FILTER clause limits the SUM to only rows where amount > 100.
  2. Step 2: Analyze the GROUP BY effect

    The query groups rows by region, then sums only amounts above 100 in each group.
  3. Final Answer:

    Sum of sales amounts greater than 100 per region. -> Option D
  4. Quick Check:

    SUM with FILTER (WHERE amount > 100) = sum of big sales [OK]
Hint: FILTER limits rows inside SUM to amount > 100 [OK]
Common Mistakes:
  • Thinking it sums all amounts, ignoring FILTER
  • Confusing SUM with COUNT
  • Ignoring GROUP BY effect
4. Identify the error in this query:
SELECT department, COUNT(*) FILTER (status = 'active') FROM employees GROUP BY department;
medium
A. Missing WHERE keyword inside FILTER clause.
B. GROUP BY should include status column.
C. COUNT(*) cannot be used with FILTER.
D. FILTER clause must be outside aggregate function.

Solution

  1. Step 1: Check FILTER clause syntax

    FILTER requires a WHERE keyword before the condition: FILTER (WHERE condition).
  2. Step 2: Verify other parts

    GROUP BY on department is correct. COUNT(*) works with FILTER. FILTER must be inside aggregate function.
  3. Final Answer:

    Missing WHERE keyword inside FILTER clause. -> Option A
  4. Quick Check:

    FILTER syntax needs WHERE [OK]
Hint: Always include WHERE inside FILTER parentheses [OK]
Common Mistakes:
  • Omitting WHERE in FILTER
  • Placing FILTER outside aggregate
  • Adding unnecessary columns to GROUP BY
5. You want to find the total sales and the total sales above 500 for each store in one query. Which query correctly uses FILTER to achieve this?
hard
A. SELECT store, SUM(amount) FILTER (WHERE amount > 500) AS total_sales, SUM(amount) AS big_sales FROM sales GROUP BY store;
B. SELECT store, SUM(amount) AS total_sales, COUNT(amount) FILTER (WHERE amount > 500) AS big_sales FROM sales GROUP BY store;
C. SELECT store, SUM(amount) AS total_sales, SUM(amount) FILTER (WHERE amount > 500) AS big_sales FROM sales GROUP BY store;
D. SELECT store, COUNT(amount) AS total_sales, SUM(amount) FILTER (WHERE amount > 500) AS big_sales FROM sales GROUP BY store;

Solution

  1. Step 1: Identify total sales calculation

    Total sales is the sum of all amounts per store, so SUM(amount) without filter is correct.
  2. Step 2: Identify big sales calculation

    Big sales are sums of amounts greater than 500, so SUM(amount) FILTER (WHERE amount > 500) is correct.
  3. Step 3: Check options

    SELECT store, SUM(amount) AS total_sales, SUM(amount) FILTER (WHERE amount > 500) AS big_sales FROM sales GROUP BY store; correctly assigns total_sales and big_sales. The other options mix sums and counts incorrectly or swap columns.
  4. Final Answer:

    SELECT store, SUM(amount) AS total_sales, SUM(amount) FILTER (WHERE amount > 500) AS big_sales FROM sales GROUP BY store; -> Option C
  5. Quick Check:

    SUM with and without FILTER for totals [OK]
Hint: Use SUM(amount) and SUM(amount) FILTER (WHERE ...) together [OK]
Common Mistakes:
  • Swapping filtered and unfiltered sums
  • Using COUNT instead of SUM for amounts
  • Misplacing FILTER clause
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard