4 Tricky SQL Questions for Data Scientists in 2021
By: Leihua Ye, Ph.D. Researcher
Tags: Programming, Sql, Data Science, Data Management, Interview

TL;DR

How to deal with duplicates? Talk about duplicates beforehand Conditional selection based on multiple variables: include them all in your WHERE clauses. Two steps of approaching “No-Sales-in-2020”: 1. Include cases with sales in 2020; 2. Exclude these cases How to handle null values? IFNULL(). Do you know OFFSET?

Photo by Jonathan Cooper on Unsplash

#1. Classes More Than 5 Students @ LeetCode

There is a table courses with columns: student and class. Please list out all classes which have more than or equal to 5 students. For example, the table:

+---------+------------+

| student | class |

+---------+------------+

| A | Math |

| B | English |

| C | Math |

| D | Biology |

| E | Math |

| F | Computer |

| G | Math |

| H | Math |

| I | Math |

+---------+------------+

Should output:

+---------+

| class |

+---------+

| Math |

+---------+

Note:

The students should not be counted duplicate in each course.

Walking Through My Thinking

Even for absolute beginners, this is an easy question: the underlying idea is to filter classes with 5 or more students and do something like this:

Incorrect Code

SELECT class

FROM courses

GROUP BY class

HAVING COUNT(student)>=5

You will bump into an error message if you submit the above code at LeetCode.

The tricky part is that there may be duplicates, and the last line of code, the HAVING COUNT() statement, fails to consider such a scenario. Instead, we should use the DISTINCT method inside the chunk to specify the output.

In fact, the question has an additional note that specifies what to do with duplicates.

A piece of advice is to ask for clarification questions if you are doing a SQL interview for DS positions. Smooth communication in any interview goes a long way.

Solution

# Write your MySQL query statement below

SELECT class

FROM courses

GROUP BY class

HAVING COUNT(DISTINCT student)>=5

Photo by Cade Roberts on Unsplash

#2. Game Play Analysis II @ LeetCode

Table: Activity

+--------------+---------+

| Column Name | Type |

+--------------+---------+

| player_id | int |

| device_id | int |

| event_date | date |

| games_played | int |

+--------------+---------+

(player_id, event_date) is the primary key of this table.

This table shows the activity of players of some game.

Each row is a record of a player who logged in and played a number of games (possibly 0) before logging out on some day using some device.

Write a SQL query that reports the device that is first logged in for each player.

The query result format is in the following example:

Activity table:

+-----------+-----------+------------+--------------+

| player_id | device_id | event_date | games_played |

+-----------+-----------+------------+--------------+

| 1 | 2 | 2016-03-01 | 5 |

| 1 | 2 | 2016-05-02 | 6 |

| 2 | 3 | 2017-06-25 | 1 |

| 3 | 1 | 2016-03-02 | 0 |

| 3 | 4 | 2018-07-03 | 5 |

+-----------+-----------+------------+--------------+ Result table:

+-----------+-----------+

| player_id | device_id |

+-----------+-----------+

| 1 | 2 |

| 2 | 3 |

| 3 | 1 |

+-----------+-----------+

Walking Through My Thinking

OMG, this question appears to be so easy but deceivingly difficult.

Here is why.

The result table contains two columns: player_id and device_id. We can use a WITH() clause to filter out the first log-in date, which can be obtained using MIN() command for each player and then write an outer query to find these two columns.

In code, we can do something as follow:

Incorrect code:

WITH first_log AS (

SELECT player_id, device_id, MIN(event_date)

FROM Activity

GROUP BY player_id

) SELECT player_id, device_id

FROM first_log

Again, correct result if run it, but an error message if submit. Try it here: LeetCode.

But why?

Before reading on, I’d suggest a short break and take a look at the code: why doesn’t it work?

The answer is each player has his/her own first log-in date, and we have to filter cases using these two columns together: player_id and event_date. In other words, each player has his/her unique minimal date.

Solution

# Write your MySQL query statement below SELECT player_id, device_id

FROM Activity

WHERE (player_id, event_date) IN (

select player_id, MIN(event_date)

from Activity

group by player_id

)

Note: don’t forget to include a pair of parenthesis.

Photo by Gary Wann on Unsplash

#3. Sellers With No Sales @ LeetCode

Table: Customer

+---------------+---------+

| Column Name | Type |

+---------------+---------+

| customer_id | int |

| customer_name | varchar |

+---------------+---------+

customer_id is the primary key for this table.

Each row of this table contains the information of each customer in the WebStore.

Table: Orders

+---------------+---------+

| Column Name | Type |

+---------------+---------+

| order_id | int |

| sale_date | date |

| order_cost | int |

| customer_id | int |

| seller_id | int |

+---------------+---------+

order_id is the primary key for this table.

Each row of this table contains all orders made in the webstore.

sale_date is the date when the transaction was made between the customer (customer_id) and the seller (seller_id).

Table: Seller

+---------------+---------+

| Column Name | Type |

+---------------+---------+

| seller_id | int |

| seller_name | varchar |

+---------------+---------+

seller_id is the primary key for this table.

Each row of this table contains the information of each seller.

Write an SQL query to report the names of all sellers who did not make any sales in 2020. Return the result table ordered by seller_name in ascending order. The query result format is in the following example.

Customer table:

+--------------+---------------+

| customer_id | customer_name |

+--------------+---------------+

| 101 | Alice |

| 102 | Bob |

| 103 | Charlie |

+--------------+---------------+ Orders table:

+-------------+------------+--------------+-------------+-------------+

| order_id | sale_date | order_cost | customer_id | seller_id |

+-------------+------------+--------------+-------------+-------------+

| 1 | 2020-03-01 | 1500 | 101 | 1 |

| 2 | 2020-05-25 | 2400 | 102 | 2 |

| 3 | 2019-05-25 | 800 | 101 | 3 |

| 4 | 2020-09-13 | 1000 | 103 | 2 |

| 5 | 2019-02-11 | 700 | 101 | 2 |

+-------------+------------+--------------+-------------+-------------+ Seller table:

+-------------+-------------+

| seller_id | seller_name |

+-------------+-------------+

| 1 | Daniel |

| 2 | Elizabeth |

| 3 | Frank |

+-------------+-------------+ Result table:

+-------------+

| seller_name |

+-------------+

| Frank |

+-------------+

Daniel made 1 sale in March 2020.

Elizabeth made 2 sales in 2020 and 1 sale in 2019.

Frank made 1 sale in 2019 but no sales in 2020.

Walking Through My Thinking

First off, this is a rather simple question. I mean it this time. What turns me down and justifies its inclusion here is its lengthy description.

What to do with these three tables? Where should I start?

There is too much information, and too much information is no better than no information.

My coping strategy is to break the question down into pieces and ask two big questions:

What does the question ask for? What information is available so far?

The first step would be to take a look at the above Result table, if provided, and, if not, ask the interviewer what would be like if things work out as expected. Again, good communication is King!

Then, let’s check what available information. As for this query, the Result table only contains one column (seller_name), and it only appears in the Orders table, which also contains sale_date and order_id information. Either of these two additional variables would be sufficient to identify the year of each order.

Now, we have a good understanding of the question and have collected all the necessary information. There is no need to check the first table (Customer).

The final step is to write up the query sequence.

The question asks for sellers with no sales in 2020. If we use a WHERE clause to filter the rows for sales not in 2020, then we would eliminate cases that have sales both in 2020 and beyond, like in Elizabeth‘s case.

The following code does not work:

Incorrect Code

SELECT seller_name

FROM Seller

JOIN Orders

USING(seller_id)

WHERE LEFT(sale_date,4) != 2020

It outputs two cases: Frank (no sale in 2020) and Elizabeth (sales both in 2020 and 2019).

For a “no-sales-in-2020” question, we can find out the seller names that have sales in 2020, as a first step, and then use an outer query to filter them out in the following step.

Solution

SELECT seller_name

FROM Seller

WHERE seller_id NOT IN (

SELECT DISTINCT seller_id

FROM Orders

WHERE LEFT(sale_date, 4) = ‘2020’

)

ORDER BY seller_name

Photo by Rod Long on Unsplash

#4. Second Highest Salary @ LeetCode

Write a SQL query to get the second highest salary from the Employee table.

+----+--------+

| Id | Salary |

+----+--------+

| 1 | 100 |

| 2 | 200 |

| 3 | 300 |

+----+--------+

For example, given the above Employee table, the query should return 200 as the second highest salary. If there is no second highest salary, then the query should return null .

+---------------------+

| SecondHighestSalary |

+---------------------+

| 200 |

+---------------------+

Walking Through My Thinking

Actually, this is a straightforward question. The reason for its inclusion is because I want to introduce two methods: IFNULL() and OFFSET.

The question asks for the second highest salary, which reminds us of using an OFFSET method to skip the first row. Also, it returns null if there is no such value. In so doing, we can use IFNULL() function.

As a side note, the function has the following form: IFNULL(statement, NULL). If there is no null value, run the statement as usual; if there is a null value, return NULL or any other value as specified.

Solution