Table: Product
+--------------+---------+ | Column Name | Type | +--------------+---------+ | product_id | int | | product_name | varchar | | unit_price | int | +--------------+---------+ product_id is the primary key (column with unique values) of this table. Each row of this table indicates the name and the price of each product.
Table: Sales
+-------------+---------+ | Column Name | Type | +-------------+---------+ | seller_id | int | | product_id | int | | buyer_id | int | | sale_date | date | | quantity | int | | price | int | +-------------+---------+ This table can have duplicate rows. product_id is a foreign key (reference column) to the Product table. Each row of this table contains some information about one sale.
Write a solution to report the products that were only sold in the first quarter of 2019. That is, between 2019-01-01 and 2019-03-31 inclusive.
Return the result table in any order.
The result format is in the following example.
Example 1:
Input: Product table: +------------+--------------+------------+ | product_id | product_name | unit_price | +------------+--------------+------------+ | 1 | S8 | 1000 | | 2 | G4 | 800 | | 3 | iPhone | 1400 | +------------+--------------+------------+ Sales table: +-----------+------------+----------+------------+----------+-------+ | seller_id | product_id | buyer_id | sale_date | quantity | price | +-----------+------------+----------+------------+----------+-------+ | 1 | 1 | 1 | 2019-01-21 | 2 | 2000 | | 1 | 2 | 2 | 2019-02-17 | 1 | 800 | | 2 | 2 | 3 | 2019-06-02 | 1 | 800 | | 3 | 3 | 4 | 2019-05-13 | 2 | 2800 | +-----------+------------+----------+------------+----------+-------+ Output: +-------------+--------------+ | product_id | product_name | +-------------+--------------+ | 1 | S8 | +-------------+--------------+ Explanation: The product with id 1 was only sold in the spring of 2019. The product with id 2 was sold in the spring of 2019 but was also sold after the spring of 2019. The product with id 3 was sold after spring 2019. We return only product 1 as it is the product that was only sold in the spring of 2019.
Problem Overview: You need to return products that were sold only during the first quarter of 2019 (Jan 1 to Mar 31). If a product has even one sale outside this range, it must be excluded. The result includes product_id and product_name.
Approach 1: SQL JOIN + GROUP BY with Conditional Filtering (O(n) time, O(n) space)
This approach joins the Sales table with the Product table using product_id. After joining, group rows by product and analyze the sale dates for each group. The key idea is to check that the minimum sale date is on or after 2019-01-01 and the maximum sale date is on or before 2019-03-31. If both conditions hold, every sale for that product occurred inside Q1 2019.
Aggregation functions like MIN(sale_date) and MAX(sale_date) make this efficient because you avoid scanning the same product multiple times. The database engine performs a single grouped pass over the rows. This pattern is common in SQL problems that require validating constraints across grouped records.
Approach 2: SQL Subquery with NOT EXISTS / Filtering (O(n) time, O(n) space)
Another way is to first identify products that have sales outside Q1 2019. A subquery filters rows where sale_date is before 2019-01-01 or after 2019-03-31. Any product appearing in that result set should be excluded. The outer query then selects products whose product_id does not appear in that list.
This technique relies on exclusion logic using NOT IN or NOT EXISTS. It works well when the query naturally separates "invalid" rows from valid ones. Subqueries like this frequently appear in database filtering problems and are easy to reason about during interviews.
Compared to grouping, the subquery approach expresses the logic more directly: remove products with invalid dates, then return the rest. However, some SQL engines optimize grouped aggregations better, especially when indexes exist on product_id or sale_date.
Recommended for interviews: The JOIN + GROUP BY solution is usually preferred because it demonstrates strong understanding of GROUP BY aggregation and conditional filtering. The subquery version is also valid and sometimes easier to write quickly. Showing both approaches demonstrates good SQL reasoning and awareness of multiple query strategies.
This approach involves using SQL to join the Product and Sales tables on the product_id column. We filter the sales to include only those made in the first quarter of 2019 and use GROUP BY to ensure the product was sold only during this period. We left join again to ensure there are no sales for these products outside this period.
This Python solution uses Panda's DataFrame to filter sales within the first quarter of 2019 and excludes any products sold outside this period. It then finds products only sold in the specified period by subtracting sets of product IDs.
Python
JavaScript
Time Complexity: O(n + m), where n is the number of rows in the Product table and m is the number in the Sales table. Space Complexity: O(n + m) for storing filter results.
This approach involves using a subquery to find product IDs that have sales exclusively in the first quarter of 2019. We first identify sales in this period and ensure there are no other sales for these products outside this period using NOT EXISTS with filtered sales.
This SQL solution uses a subquery to verify that the product was sold in Q1 2019 and ensures no sales exist for the product outside this period.
SQL
Time Complexity: O(n*m), Space Complexity: O(1) when using database indexing.
MySQL
| Approach | Complexity |
|---|---|
| Using SQL JOIN and GROUP BY | Time Complexity: O(n + m), where n is the number of rows in the Product table and m is the number in the Sales table. Space Complexity: O(n + m) for storing filter results. |
| Using SQL Subquery | Time Complexity: O(n*m), Space Complexity: O(1) when using database indexing. |
| Default Approach | — |
| Approach | Time | Space | When to Use |
|---|---|---|---|
| JOIN + GROUP BY with MIN/MAX date checks | O(n) | O(n) | Best when validating constraints across grouped records |
| Subquery exclusion using NOT IN / NOT EXISTS | O(n) | O(n) | Useful when you can isolate invalid rows and filter them out |
LeetCode 1084: Sales Analysis III [SQL] • Frederik Müller • 5,264 views views
Watch 9 more video solutions →Practice Sales Analysis III with our built-in code editor and test cases.
Practice on FleetCodePractice this problem
Open in Editor