Here is SQL test I took during a job interview. First is the description, or you can skip directly to the answer.

Description:

As part of developing the call history functionality of a dialer application, create a query that returns a list of all contacts, the total duration of their calls, and the number of calls during the work week and weekends.

The result should have the following column: full_name | phone | type | workweek | weekend.

  • full_name - full contact name:
    • Record format is ## ##, where the placeholders are ## the order they appear:
      1. Last name of the contact
      2. First name of the contact
  • phone - phone number
  • type - call type
  • workweek - information about calls during the working week (from Monday to Friday):
    • Record format is ##:##:## (##), where the placeholders are ## in the order they appear:
      1. Hours part of the total duration of calls, numeric (00..n)
      2. Minutes part of the total duration of calls, numeric (00..59)
      3. Seconds part of the total duration of calls, numeric (00..59)
      4. Total number of calls
  • weekend - information about calls during the weekend (from Saturday to Sunday):
    • Record format is ##:##:## (##), where the placeholders are ## in the order they appear:
      1. Hours part of the total duration of calls, numeric (00..n)
      2. Minutes part of the total duration of calls, numeric (00..59)
      3. Seconds part of the total duration of calls, numeric (00..59)
      4. Total number of calls

The result should be sorted in ascending order by full_name, then in ascending order by type.

Schema:

contacts

nametypeconstraintdescription
idINTPRIMARY KEYContact ID
first_nameVARCHAR(255)Contact first name
last_nameVARCHAR(255)Contact last name
phoneVARCHAR(255)Contact phone number

calls

nametypeconstraintdescription
contact_idINTFOREIGN KEY (contact_id => contacts.id)Contact ID
dtDATETIMECall date and time
typeENUM(‘incoming’,‘outgoing’)Call type
durationSMALLINTCall duration

Sample Data Tables

contacts

idfirst_namelast_namephone
1SpencerForrestor+54 (929) 865-3063
2EllisMattiato+86 (490) 216-5428
3RobinRosendale+86 (412) 441-4721

calls

contact_iddttypeduration
12022-09-14 05:12:20incoming1531
12022-09-15 09:29:55incoming1962
12022-09-12 00:07:23outgoing1213
12022-09-12 07:05:48outgoing556
12022-09-12 11:16:21outgoing1382
12022-09-12 11:30:28outgoing2622
12022-09-14 16:02:33outgoing3390
12022-09-15 07:07:27outgoing2267
22022-09-15 00:39:01incoming127
22022-09-15 00:53:08incoming375
22022-09-13 10:47:30outgoing2907
22022-09-16 09:58:15outgoing1065
22022-09-17 10:50:01outgoing2801
32022-09-13 14:37:12incoming904
32022-09-13 22:50:33incoming2925
32022-09-12 12:25:40outgoing352
32022-09-13 23:48:02outgoing744
32022-09-14 16:59:23outgoing1067
32022-09-15 09:24:01outgoing2344
32022-09-15 12:13:39outgoing3567

Expected Output:

full_namephonetypeworkweekweekend
Forrestor Spencer+54 (929) 865-3063incoming00:58:13 (2)NULL
Forrestor Spencer+54 (929) 865-3063outgoing03:10:30 (6)NULL
Mattiato Ellis+86 (490) 216-5428incoming00:08:22 (2)NULL
Mattiato Ellis+86 (490) 216-5428outgoing01:06:12 (2)00:46:41 (1)
Rosendale Robin+86 (412) 441-4721incoming01:03:49 (2)NULL
Rosendale Robin+86 (412) 441-4721outgoing02:14:34 (5)NULL

Answer

There are three challenges to writing this query

  1. Concatenating the full name as well as number of calls to the duration. Number of calls is found via a count, grouping on the contact information.
  2. Summing then changing the total seconds of each contacts calls to HH:MM:SS (you can see how to do that in my post here)
  3. Determine if the call is a weekday or weekend and putting that sum in the correct column. Use the ISODOW PostgreSQL function.
select b.last_name || ' ' || b.first_name full_name
, b.phone
, a.type
, (sum(case when extract(isodow from dt::date) < 6 then duration else null end) * interval '1 sec')::varchar(10) || ' (' || count(case when extract(isodow from dt::date) < 6 then duration else null end) || ')' as workweek
, (sum(case when extract(isodow from dt::date) >= 6 then duration else null end) * interval '1 sec')::varchar(10) || ' (' || count(case when extract(isodow from dt::date) >= 6 then duration else null end) || ')' as weekend

from calls a
join contacts b on a.contact_id = b.id
group by b.last_name || ' ' || b.first_name, b.phone, a.type
order by b.last_name || ' ' || b.first_name, a.type;