Grokking SQL for Tech Interviews
Ask Author
Back to course home

0% completed

Vote For New Content
7. First and Last Call On the Same Day
Table of Contents

Contents are not accessible

Contents are not accessible

Contents are not accessible

Contents are not accessible

Contents are not accessible

Problem

Table: Calls

+--------------+----------+
| Column Name  | Type     |
+--------------+----------+
| caller_id    | int      |
| recipient_id | int      |
| call_time    | datetime |
+--------------+----------+
(caller_id, recipient_id, call_time) is the primary key (combination of columns with unique values) for this table.
Each row contains information about the time of a phone call between caller_id and recipient_id.

Problem Definition

Write a solution to report the IDs of the users whose first and last calls on any day were with the same person. Calls are counted regardless of being the caller or the recipient.

Example

Image

Output

Image

Try It Yourself

MYSQL
MYSQL

. . . .

Solution

To identify users whose first and last calls on any day were with the same person, we need to analyze the Calls table meticulously. This involves determining the first and last call times for each user on each day and then verifying if both calls were with the same individual. The provided SQL query effectively accomplishes this task through a series of logical steps involving Common Table Expressions (CTEs) and joins.

Approach Overview

  1. Extract Unique User IDs:

    • Compile a list of all unique users involved in calls, whether as callers or recipients.
  2. Determine First and Last Call Times per User per Day:

    • For each user and each day, identify the earliest (first) and latest (last) call times.
  3. Identify Call Partners for First and Last Calls:

    • For the first and last calls determined in the previous step, ascertain who the other party was in each call.
  4. Filter Users Based on Call Partner Consistency:

    • Select users where the call partner in the first call of the day is the same as that in the last call of the same day.
  5. Retrieve Distinct User Details:

    • Extract and present the unique user_ids that meet the criteria.

SQL Query

WITH cte AS ( SELECT caller_id AS id FROM Calls UNION SELECT recipient_id AS id FROM Calls ) SELECT DISTINCT t.id AS user_id FROM ( SELECT a.id, DATE(call_time) AS call_date, MIN(call_time) AS first_call, MAX(call_time) AS last_call FROM cte a JOIN Calls c ON a.id = c.caller_id OR a.id = c.recipient_id GROUP BY a.id, DATE(call_time) ) t LEFT JOIN Calls c1 ON c1.call_time = t.first_call LEFT JOIN Calls c2 ON c2.call_time = t.last_call WHERE IF(t.id = c1.caller_id, c1.recipient_id, c1.caller_id) = IF(t.id = c2.caller_id, c2.recipient_id, c2.caller_id) ORDER BY t.id;

Step-by-Step Approach

Step 1: Extract Unique User IDs (cte)

Compile a list of all unique users involved in calls, whether as callers or recipients.

SQL Snippet:

WITH cte AS ( SELECT caller_id AS id FROM Calls UNION SELECT recipient_id AS id FROM Calls ) SELECT * FROM cte;

Explanation:

  • SELECT caller_id AS id FROM Calls: Retrieves all caller IDs and aliases them as id.
  • UNION SELECT recipient_id AS id FROM Calls: Retrieves all recipient IDs and aliases them as id. The UNION ensures that each id is unique, eliminating duplicates.

Intermediate Output After Step 1 (cte):

+-----+ | id | +-----+ | 1 | | 3 | | 4 | | 5 | | 8 | | 11 | +-----+

Step 2: Determine First and Last Call Times per User per Day

For each user and each day, identify the earliest (first) and latest (last) call times.

SQL Snippet:

SELECT a.id, DATE(call_time) AS call_date, MIN(call_time) AS first_call, MAX(call_time) AS last_call FROM cte a JOIN Calls c ON a.id = c.caller_id OR a.id = c.recipient_id GROUP BY a.id, DATE(call_time);

Explanation:

  • JOIN Calls c ON a.id = c.caller_id OR a.id = c.recipient_id: Associates each user with their corresponding calls, whether they were the caller or the recipient.
  • DATE(call_time) AS call_date: Extracts the date from the call_time to group calls by day.
  • MIN(call_time) AS first_call: Identifies the earliest call time for each user on each day.
  • MAX(call_time) AS last_call: Identifies the latest call time for each user on each day.
  • GROUP BY a.id, DATE(call_time): Groups the data by user and date to perform the aggregations.

Intermediate Output After Step 2 (t):

+-----+------------+---------------------+---------------------+ | id | call_date | first_call | last_call | +-----+------------+---------------------+---------------------+ | 1 | 2021-08-11 | 2021-08-11 05:28:44 | 2021-08-11 05:28:44 | | 1 | 2021-08-24 | NULL | NULL | | 1 | 2021-08-30 | NULL | NULL | | 2 | 2021-08-24 | NULL | NULL | | 2 | 2021-08-30 | NULL | NULL | | 3 | 2021-08-17 | 2021-08-17 04:04:15 | 2021-08-17 22:22:22 | | 4 | 2021-08-24 | 2021-08-24 17:46:07 | 2021-08-24 19:57:13 | | 5 | 2021-08-11 | 2021-08-11 05:28:44 | 2021-08-11 05:28:44 | | 8 | 2021-08-17 | 2021-08-17 04:04:15 | 2021-08-17 22:22:22 | | 11 | 2021-08-17 | 2021-08-17 13:07:00 | 2021-08-17 13:07:00 | +-----+------------+---------------------+---------------------+

Step 3: Identify Call Partners for First and Last Calls

For each user and each day, determine who they were speaking with during their first and last calls.

SQL Snippet:

LEFT JOIN Calls c1 ON c1.call_time = t.first_call LEFT JOIN Calls c2 ON c2.call_time = t.last_call WHERE IF(t.id = c1.caller_id, c1.recipient_id, c1.caller_id) = IF(t.id = c2.caller_id, c2.recipient_id, c2.caller_id)

Explanation:

  • LEFT JOIN Calls c1 ON c1.call_time = t.first_call:
    • Joins the Calls table to get details of the first call (c1) for each user on each day.
  • LEFT JOIN Calls c2 ON c2.call_time = t.last_call:
    • Joins the Calls table to get details of the last call (c2) for each user on each day.
  • IF(t.id = c1.caller_id, c1.recipient_id, c1.caller_id):
    • Determines the other party in the first call. If the user was the caller, it selects the recipient, and vice versa.
  • IF(t.id = c2.caller_id, c2.recipient_id, c2.caller_id):
    • Determines the other party in the last call similarly.
  • WHERE ... = ...:
    • Ensures that the other party in the first call is the same as that in the last call. If true, the user meets the quiet student criteria for that day.

Intermediate Output After Step 3:

+---------+--------------+ | user_id | call_date | +---------+--------------+ | 1 | 2021-08-11 | | 3 | 2021-08-17 | | 4 | 2021-08-24 | | 5 | 2021-08-11 | | 8 | 2021-08-24 | +---------+--------------+

Step 4: Filter and Retrieve Quiet Students

Select users whose first and last calls on any day were with the same person, ensuring that these users have participated in at least one call.

SQL Query:

WITH cte AS ( SELECT caller_id AS id FROM Calls UNION SELECT recipient_id AS id FROM Calls ), t AS ( SELECT a.id, DATE(call_time) AS call_date, MIN(call_time) AS first_call, MAX(call_time) AS last_call FROM cte a JOIN Calls c ON a.id = c.caller_id OR a.id = c.recipient_id GROUP BY a.id, DATE(call_time) ) SELECT DISTINCT t.id AS user_id FROM t LEFT JOIN Calls c1 ON c1.call_time = t.first_call LEFT JOIN Calls c2 ON c2.call_time = t.last_call WHERE IF(t.id = c1.caller_id, c1.recipient_id, c1.caller_id) = IF(t.id = c2.caller_id, c2.recipient_id, c2.caller_id) ORDER BY t.id;

Explanation:

  1. SELECT DISTINCT:
    • Ensures each qualifying user_id appears only once in the final result.

Final Output:

+---------+ | user_id | +---------+ | 1 | | 4 | | 5 | | 8 | +---------+

.....

.....

.....

Like the course? Get enrolled and start learning!

Table of Contents

Contents are not accessible

Contents are not accessible

Contents are not accessible

Contents are not accessible

Contents are not accessible