Hello! Welcome to the final lesson in our module on connecting product data.
Introduction
In our last session, we explored how to use LEFT JOIN to find not only where relationships exist between tables but also where they don't—a powerful technique for identifying users who haven't performed a specific action. We saw that JOIN operations create a temporary, combined table from multiple sources.
Today, we'll learn how to apply the WHERE clause to this combined table. You're already familiar with using WHERE to filter a single table, but applying it to a JOIN result unlocks a much deeper level of analysis.
This lesson directly addresses the learning outcome: Apply the WHERE clause to filter the results of a joined table. By the end of this session, you'll be able to ask highly specific, multi-table questions, such as "Show me all the premium feature events triggered by users who signed up from our latest marketing campaign." This is a fundamental skill for effective user segmentation.
1. The Basic Principle: Join First, Filter Second
The most important concept to grasp is the logical order of operations in a SQL query:
FROM/JOIN: The database first performs the join, creating a new, temporary table in memory that combines columns from all the tables you've specified.WHERE: TheWHEREclause is then applied to this new, temporary table, filtering out rows that don't meet your conditions.SELECT: Finally, theSELECTstatement picks the columns you want to see from the remaining rows.
Think of it like a two-step process in a design tool: first, you group several objects together (JOIN), and then you apply a filter or style to that entire group (WHERE).
Let's start with a resource that provides a clear definition and a simple, practical example.
SQL JOIN WHERE - Syntax, Use Cases, and Examples
This article from Hightouch clearly explains the concept of applying a WHERE clause after a JOIN and provides a clean, easy-to-follow example.
Please read the sections 'What is SQL JOIN with WHERE Clause?', 'When you would use it', 'Syntax', and the 'Example query' with its 'Example table response'. Notice how the JOIN first combines the orders and customers tables, and then the WHERE clause filters this combined result to only show customers from 'New York'.
2. Filtering INNER JOIN Results
Let's apply this to a common product scenario. Imagine we have a users table and an events table. We want to find all events performed by users who signed up as part of a specific campaign.
Here’s how we would structure the query:
SELECT
u.email,
e.event_name,
e.event_timestamp
FROM
users AS u
INNER JOIN
events AS e ON u.user_id = e.user_id
WHERE
u.signup_campaign = 'Summer_Promo_2024';
In this query:
INNER JOINcreates a large set of rows, matching every user with every event they have ever performed.WHERE u.signup_campaign = 'Summer_Promo_2024'then filters that large set, keeping only the rows where the user came from the 'Summer_Promo_2024' campaign.
The following video provides an excellent visual walkthrough of this process. Although the example is about chemical compounds, the logic is identical.
This video from Decomplexify provides a great visual walkthrough of building a query step-by-step. It first joins three tables and then applies a WHERE clause to filter the results to answer a specific question.
Please watch from 06:28 to 09:09. Pay attention to how the narrator first explains the result of the INNER JOIN and then adds the WHERE clause to narrow down the results to only those rows related to 'Hydrogen'. This demonstrates the logical order: join first, then filter.
3. A Critical Distinction: WHERE vs. ON with LEFT JOIN
In the previous lesson, you learned to use WHERE ... IS NULL with a LEFT JOIN. But what happens when you use other conditions? The placement of your filter—in the ON clause or the WHERE clause—becomes critically important with LEFT JOIN.
-
Condition in
WHERE: Filters the final result set after the join. If you filter on a column from the right table (e.g.,WHERE events.event_name = 'button_click'), you implicitly discard all the rows where that column isNULL. This effectively turns yourLEFT JOINinto anINNER JOIN, because you lose all the users who didn't perform that event. -
Condition in
ON: Filters the right table before the join is performed. This is useful when you want to keep all rows from the left table but only join them to a specific subset of rows from the right table.
Let's illustrate with a product question: "Show me all users, and for each user, list only their 'add_to_cart' events."
Incorrect Approach (using WHERE):
SELECT u.user_id, e.event_name
FROM users AS u
LEFT JOIN events AS e ON u.user_id = e.user_id
WHERE e.event_name = 'add_to_cart';
This query will only return users who have 'add_to_cart' events. It fails to show users who have never added anything to their cart.
Correct Approach (using ON):
SELECT u.user_id, e.event_name
FROM users AS u
LEFT JOIN events AS e ON u.user_id = e.user_id AND e.event_name = 'add_to_cart';
This query returns all users. For users who have 'add_to_cart' events, it shows them. For all other users, e.event_name will be NULL.
This is a subtle but powerful difference. The following resource provides an excellent, detailed example that breaks this down.
SQL JOIN: what is the difference between WHERE clause ...
Let's explore the critical nuance of where to place a filter condition. This Stack Overflow answer provides an excellent, detailed example with intermediate tables, which is very helpful for visualizing the difference.
Read the second answer on the page (by Sandeep Jindal). Focus on the two examples 'a) Inside WHERE clause' and 'b) Inside JOIN clause'. Compare the intermediate tables and the final results. This will clarify how the placement of the filter condition dramatically changes the output of a LEFT JOIN.
Rule of Thumb:
- Conditions that link the tables go in the
ONclause. - Conditions that filter the final, combined result go in the
WHEREclause.
4. Practice Exercise
Let's put this all together with a scenario you might encounter as a product designer.
Scenario:
You work at a project management tool company. You want to understand how users who signed up through a specific partner (PartnerA) are using the "task_completed" feature.
You have two tables:users table:
| user_id | signup_source | |
|---|---|---|
| 1 | sara@email.com | Organic |
| 2 | mike@email.com | PartnerA |
| 3 | jen@email.com | PartnerA |
| 4 | leo@email.com | PartnerB |
events table:
| event_id | user_id | event_name | details |
|---|---|---|---|
| 101 | 2 | task_created | {"priority": "high"} |
| 102 | 1 | project_created | {"template": "kanban"} |
| 103 | 3 | task_completed | {"time_taken": 35} |
| 104 | 2 | task_completed | {"time_taken": 120} |
| 105 | 2 | comment_added | {"length": 140} |
Your Task:
Write a SQL query to find the email addresses of users who signed up via PartnerA and have performed a task_completed event.
Think about the steps:
- Which tables do you need to join?
- What kind of join is appropriate? (
INNERorLEFT?) - What are your filtering conditions?
Click here to see the solution
SELECT
u.email
FROM
users AS u
INNER JOIN
events AS e ON u.user_id = e.user_id
WHERE
u.signup_source = 'PartnerA' AND e.event_name = 'task_completed';
Explanation:
SELECT u.email: We want the email of the qualifying users.FROM users AS u INNER JOIN events AS e ON u.user_id = e.user_id: We use anINNER JOINbecause we are only interested in users who have performed events. This links users to their corresponding events.WHERE u.signup_source = 'PartnerA' AND e.event_name = 'task_completed': This is the filtering step. We apply two conditions to the joined table:- The user must have come from
PartnerA. - The event name must be
task_completed.
- The user must have come from
- The
ANDoperator ensures that both conditions must be true for a row to be included.
This query would correctly return the email for user mike@email.com and jen@email.com. (Note: The query asks for emails, so the result would be mike@email.com and jen@email.com. The solution in the details block was slightly off, this is the correct logic). Let's fix that. The query should return mike@email.com and jen@email.com. Wait, Jen is user 3, Mike is user 2. Jen has one task_completed event. Mike has one task_completed event. Both are from PartnerA. So yes, the query should return both emails. Let me re-check the solution. The query is correct. The result should be mike@email.com and jen@email.com. I'll just state the correct result.
Corrected Result: The query would return mike@email.com and jen@email.com.
Conclusion
Congratulations on completing the "Connecting Product Data with Joins" module! You've built a solid foundation, moving from querying single tables to combining multiple data sources and filtering them to get precise answers.
Key Takeaways:
- The
WHEREclause filters the rows of the temporary table created by aJOIN. - The logical order of operations is
JOIN->WHERE->SELECT. - For
INNER JOIN, it's best practice to keep join logic inONand filter logic inWHERE. - For
LEFT JOIN, the placement of a filter is critical:- In
WHERE, it filters the final result. - In
ON, it filters the right table before the join.
- In
Preview of the Next Lesson
You now have the skills to select, join, and filter data to get specific lists of users, events, and other entities. The next step in your data journey is to move from retrieving lists to calculating metrics.
In our next module, "Calculating Core Product Metrics," we will start with the COUNT() function. This will enable you to answer questions like, "How many users signed up last week?" and "How many 'add to cart' events happened yesterday?" This is the gateway to building dashboards and tracking your product's key performance indicators (KPIs).
Can't find a good explanation? Sign up and we'll make it for you
Sign up