Watch the video solution for NPV Queries, a easy level problem involving Database. This walkthrough by Everyday Data Science has 6,071 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
Table: NPV
+---------------+---------+ | Column Name | Type | +---------------+---------+ | id | int | | year | int | | npv | int | +---------------+---------+ (id, year) is the primary key (combination of columns with unique values) of this table. The table has information about the id and the year of each inventory and the corresponding net present value.
Table: Queries
+---------------+---------+ | Column Name | Type | +---------------+---------+ | id | int | | year | int | +---------------+---------+ (id, year) is the primary key (combination of columns with unique values) of this table. The table has information about the id and the year of each inventory query.
Write a solution to find the npv of each query of the Queries table.
Return the result table in any order.
The result format is in the following example.
Example 1:
Input: NPV table: +------+--------+--------+ | id | year | npv | +------+--------+--------+ | 1 | 2018 | 100 | | 7 | 2020 | 30 | | 13 | 2019 | 40 | | 1 | 2019 | 113 | | 2 | 2008 | 121 | | 3 | 2009 | 12 | | 11 | 2020 | 99 | | 7 | 2019 | 0 | +------+--------+--------+ Queries table: +------+--------+ | id | year | +------+--------+ | 1 | 2019 | | 2 | 2008 | | 3 | 2009 | | 7 | 2018 | | 7 | 2019 | | 7 | 2020 | | 13 | 2019 | +------+--------+ Output: +------+--------+--------+ | id | year | npv | +------+--------+--------+ | 1 | 2019 | 113 | | 2 | 2008 | 121 | | 3 | 2009 | 12 | | 7 | 2018 | 0 | | 7 | 2019 | 0 | | 7 | 2020 | 30 | | 13 | 2019 | 40 | +------+--------+--------+ Explanation: The npv value of (7, 2018) is not present in the NPV table, we consider it 0. The npv values of all other queries can be found in the NPV table.
Problem Overview: The database contains two tables: NPV(id, year, npv) and Queries(id, year). For every query pair (id, year), return the corresponding NPV value. If the pair does not exist in the NPV table, return 0 instead.
Approach 1: LEFT JOIN with IFNULL (O(n) time, O(1) extra space)
The most direct solution uses a LEFT JOIN between Queries and NPV on both id and year. A left join guarantees every row from Queries appears in the result even when no matching record exists in NPV. When a match is missing, SQL returns NULL for the npv column. Use IFNULL(npv, 0) (or COALESCE) to replace that NULL value with 0. The database performs the join once across the two tables, giving linear performance relative to the number of rows scanned. This approach is concise, efficient, and the typical pattern used for handling missing relational data.
This technique relies on core concepts from SQL and database querying. Specifically, you match rows using a composite join condition Queries.id = NPV.id AND Queries.year = NPV.year. The result set directly produces the required columns: the query identifiers plus the computed NPV value.
Approach 2: Correlated Subquery with COALESCE (O(n) time, O(1) extra space)
Another option retrieves the NPV value using a correlated subquery. For each row in Queries, run a subquery that searches the NPV table for the matching (id, year). If the subquery returns NULL or no result, wrap it with COALESCE(..., 0) to return 0. This approach is logically straightforward because it mirrors the problem statement: for each query, look up the NPV value.
While the complexity is still roughly linear for small datasets due to database optimization, correlated subqueries can be less efficient on large tables compared to joins. Most query planners internally transform this pattern into a join anyway. Still, understanding both forms is useful when working with SQL joins and relational lookups.
Recommended for interviews: The LEFT JOIN approach is the expected solution. It shows you understand relational joins and how to handle missing matches using IFNULL or COALESCE. The subquery version demonstrates equivalent logic but is less commonly preferred because joins scale better and are easier to optimize.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| LEFT JOIN with IFNULL | O(n) | O(1) | Standard relational lookup when you must return all rows from Queries even if no match exists |
| Correlated Subquery with COALESCE | O(n) | O(1) | When expressing logic per-row is clearer or when joins are restricted |