1811. Find Interview Candidates


Problem Description

In this problem, we have two SQL tables: Contests and Users.

The Contests table has the following columns:

  • contest_id (integer): the primary key for this table, representing the contest ID.
  • gold_medal (integer): the user ID of the gold medalist.
  • silver_medal (integer): the user ID of the silver medalist.
  • bronze_medal (integer): the user ID of the bronze medalist.

The Users table has the following columns:

  • user_id (integer): the primary key for this table, representing the user ID.
  • mail (varchar): the email address of the user.
  • name (varchar): the name of the user.

The problem requires us to write an SQL query to report the name and the mail of all interview candidates. A user is considered an interview candidate if at least one of these two conditions is true:

  1. The user won any medal in three or more consecutive contests.
  2. The user won the gold medal in three or more different contests (not necessarily consecutive).

Example

Let's walk through the example given in the problem description to understand the requirements clearly:

Contests table:

1+------------+------------+--------------+--------------+
2| contest_id | gold_medal | silver_medal | bronze_medal |
3+------------+------------+--------------+--------------+
4| 190        | 1          | 5            | 2            |
5| 191        | 2          | 3            | 5            |
6| 192        | 5          | 2            | 3            |
7| 193        | 1          | 3            | 5            |
8| 194        | 4          | 5            | 2            |
9| 195        | 4          | 2            | 1            |
10| 196        | 1          | 5            | 2            |
11+------------+------------+--------------+--------------+

Users table:

1+---------+--------------------+-------+
2| user_id | mail               | name  |
3+---------+--------------------+-------+
4| 1       | [email protected] | Sarah |
5| 2       | [email protected]   | Bob   |
6| 3       | [email protected] | Alice |
7| 4       | [email protected] | Hercy |
8| 5       | [email protected] | Quarz |
9+---------+--------------------+-------+

Result table:

1+-------+--------------------+
2| name  | mail               |
3+-------+--------------------+
4| Sarah | [email protected] |
5| Bob   | [email protected]   |
6| Alice | [email protected] |
7| Quarz | [email protected] |
8+-------+--------------------+

Explanation:

  • Sarah won 3 gold medals (190, 193, and 196), so we include her in the result table.
  • Bob won a medal in 3 consecutive contests (190, 191, and 192), so we include him in the result table.
    • Note that he also won a medal in 3 other consecutive contests (194, 195, and 196).
  • Alice won a medal in 3 consecutive contests (191, 192, and 193), so we include her in the result table.
  • Quarz won a medal in 5 consecutive contests (190, 191, 192, 193, and 194), so we include them in the result table.

Approach

To solve this problem, we can combine the information from both tables and use the aggregation feature of SQL to count the number of consecutive contest wins and the number of gold medals won by each user.

  1. First, we will create a temporary table that stores all the medals won by each user, along with their contest IDs.
  2. In the next step, we will count the number of gold medals won by each user and join the results with the Users table.
  3. We will then add a column with the number of consecutive contest wins for each user by counting their consecutive contests.
  4. Finally, we will select only users who meet at least one of the two conditions and return their name and email.

SQL Query

Here's the SQL query that implements the approach described above:

1WITH medal_counts AS (
2    SELECT user_id, contest_id, contest_id - ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY contest_id) AS group_id
3    FROM (
4        SELECT gold_medal AS user_id, contest_id FROM Contests
5        UNION ALL
6        SELECT silver_medal AS user_id, contest_id FROM Contests
7        UNION ALL
8        SELECT bronze_medal AS user_id, contest_id FROM Contests
9    ) medals
10)
11, gold_medals AS (
12    SELECT user_id, COUNT(*) AS gold_medal_count
13    FROM Contests
14    GROUP BY user_id
15)
16SELECT u.name, u.mail
17FROM Users u
18JOIN gold_medals gm ON u.user_id = gm.user_id
19WHERE gm.gold_medal_count >= 3
20OR EXISTS (
21    SELECT 1
22    FROM medal_counts
23    WHERE user_id = u.user_id
24    GROUP BY user_id, group_id
25    HAVING COUNT(*) >= 3
26)

The query first creates a temporary table with all medals won by each user and another temporary table with the count of gold medals won by each user. Then it selects users who have won 3 or more gold medals or have won any medals in 3 or more consecutive contests.## Alternative Approach

Another approach is to first find all users who won a medal in three or more consecutive contests, and then find all users who won the gold medal in three or more different contests. Finally, we can union these results and join them with the Users table to obtain their name and email.

SQL Query

Here's the SQL query that implements the alternative approach:

1WITH medals AS (
2    SELECT DISTINCT user_id, contest_id
3    FROM (
4        SELECT gold_medal AS user_id, contest_id FROM Contests
5        UNION ALL
6        SELECT silver_medal AS user_id, contest_id FROM Contests
7        UNION ALL
8        SELECT bronze_medal AS user_id, contest_id FROM Contests
9    ) medals
10)
11, consecutive_medals AS (
12    SELECT user_id
13    FROM (
14        SELECT user_id, contest_id, contest_id - ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY contest_id) AS group_id
15        FROM medals
16    ) medal_group
17    GROUP BY user_id, group_id
18    HAVING COUNT(*) >= 3
19)
20, gold_medalists AS (
21    SELECT user_id
22    FROM Contests
23    GROUP BY user_id
24    HAVING COUNT(gold_medal) >= 3
25)
26
27SELECT u.name, u.mail
28FROM Users u
29WHERE EXISTS (SELECT 1 FROM consecutive_medals WHERE user_id = u.user_id)
30OR EXISTS (SELECT 1 FROM gold_medalists WHERE user_id = u.user_id)

This query first creates a temporary table with all unique medal winning user_ids and contest_ids. It then finds users who won a medal in three or more consecutive contests and users who won the gold medal in three or more different contests. Finally, it selects users that meet either of the conditions and returns their name and email.

Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:

Which two pointer techniques do you use to check if a string is a palindrome?

Solution Implementation


Fast Track Your Learning with Our Quick Skills Quiz:

What's the output of running the following function using input 56?

1KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13    def dfs(path, res):
14        if len(path) == len(digits):
15            res.append(''.join(path))
16            return
17
18        next_number = digits[len(path)]
19        for letter in KEYBOARD[next_number]:
20            path.append(letter)
21            dfs(path, res)
22            path.pop()
23
24    res = []
25    dfs([], res)
26    return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2    '2', "abc".toCharArray(),
3    '3', "def".toCharArray(),
4    '4', "ghi".toCharArray(),
5    '5', "jkl".toCharArray(),
6    '6', "mno".toCharArray(),
7    '7', "pqrs".toCharArray(),
8    '8', "tuv".toCharArray(),
9    '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13    List<String> res = new ArrayList<>();
14    dfs(new StringBuilder(), res, digits.toCharArray());
15    return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19    if (path.length() == digits.length) {
20        res.add(path.toString());
21        return;
22    }
23    char next_digit = digits[path.length()];
24    for (char letter : KEYBOARD.get(next_digit)) {
25        path.append(letter);
26        dfs(path, res, digits);
27        path.deleteCharAt(path.length() - 1);
28    }
29}
30
1const KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13    let res = [];
14    dfs(digits, [], res);
15    return res;
16}
17
18function dfs(digits, path, res) {
19    if (path.length === digits.length) {
20        res.push(path.join(''));
21        return;
22    }
23    let next_number = digits.charAt(path.length);
24    for (let letter of KEYBOARD[next_number]) {
25        path.push(letter);
26        dfs(digits, path, res);
27        path.pop();
28    }
29}
30

Recommended Readings


Got a question? Ask the Monster Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


🪄