Grokking SQL for Tech Interviews
Ask Author
Back to course home

0% completed

Vote For New Content
16. Order Fulfillment Rate (Medium)
On this page

Problem Statement

Example

Try It Yourself

Solution

Approach Overview

SQL Query

Step 1: Calculate Fulfillment Rate for Each Order (OrderFulfillment CTE)

Step 2: Aggregate Fulfillment Rate for Each Customer (CustomerFulfillment CTE)

Step 3: Retrieve the Final Results

Problem Statement

Table: Orders
Each row in this table represents an individual order placed by a customer, detailing the unique order ID, customer ID, and the timestamp when the order was placed.

+---------------+------------+
| Column Name   | Type       | 
+---------------+------------+
| order_id      | int        | 
| customer_id   | int        |
| time_stamp    | datetime   |
+---------------+------------+
order_id is the primary key for this table.

Table: Deliveries
This table tracks the status of each order's delivery, including the order ID, the timestamp of delivery attempt, and the delivery status.

+---------------+------------+-----------------------+
| Column Name   | Type       | Enum                  |
+---------------+------------+-----------------------+
| order_id      | int        |                       |
| time_stamp    | datetime   |                       |
| status        | ENUM       | 'delivered', 'failed' |
+---------------+------------+-----------------------+
(order_id, time_stamp) is the primary key for this table.
order_id is a foreign key to the Orders table.

Develop a solution to calculate the fulfillment rate for each customer based on their orders. The fulfillment rate of an order is calculated as the number of 'delivered' statuses divided by the total number of delivery attempts for that order. The fulfillment rate of an order that did not have any delivery attempts is considered 0. Round the fulfillment rate to two decimal places.

Return the result table in any order.

Example

Input:

Orders table: +----------+-------------+---------------------+ | order_id | customer_id | time_stamp | +----------+-------------+---------------------+ | 1 | 100 | 2020-03-21 10:16:13 | | 2 | 200 | 2020-01-04 13:57:59 | | 3 | 100 | 2020-07-29 23:09:44 | | 4 | 300 | 2020-12-09 10:39:37 | +----------+-------------+---------------------+
Deliveries table: +----------+---------------------+-----------+ | order_id | time_stamp | status | +----------+---------------------+-----------+ | 1 | 2020-03-22 09:00:00 | delivered | | 1 | 2020-03-22 15:00:00 | failed | | 2 | 2020-01-05 14:00:00 | delivered | | 3 | 2020-08-01 00:00:00 | delivered | | 3 | 2020-08-01 12:00:00 | delivered | | 4 | 2020-12-10 11:00:00 | failed | +----------+---------------------+-----------+

Output:

+-------------+-------------------+ | customer_id | fulfillment_rate | +-------------+-------------------+ | 100 | 0.75 | | 200 | 1.00 | | 300 | 0.00 | +-------------+-------------------+

Try It Yourself

MYSQL
MYSQL

. . . .

Solution

To calculate the fulfillment rate for each customer based on their orders, we need to analyze the Orders and Deliveries tables.

Approach Overview

  1. Calculate Fulfillment Rate for Each Order:

    • For each order, determine the number of 'delivered' delivery attempts.
    • Calculate the total number of delivery attempts (both 'delivered' and 'failed').
    • Compute the fulfillment rate as the ratio of delivered attempts to total attempts.
    • If there are no delivery attempts, assign a fulfillment rate of 0.
  2. Calculate Fulfillment Rate for Each Customer:

    • For each customer, average the fulfillment rates of all their orders.
    • Round the resulting fulfillment rate to two decimal places.
  3. Present the Results:

    • Display each customer's ID alongside their calculated fulfillment rate.

The provided SQL query utilizes Common Table Expressions (CTEs) to structure this solution effectively.

SQL Query

WITH OrderFulfillment AS ( -- Calculate the fulfillment rate for each order SELECT o.order_id, o.customer_id, IFNULL(SUM(CASE WHEN d.status = 'delivered' THEN 1 ELSE 0 END) / COUNT(d.order_id), 0) AS fulfillment_rate FROM Orders o LEFT JOIN Deliveries d ON o.order_id = d.order_id GROUP BY o.order_id, o.customer_id ), CustomerFulfillment AS ( -- Aggregate the fulfillment rate for each customer SELECT customer_id, ROUND(AVG(fulfillment_rate), 2) AS fulfillment_rate FROM OrderFulfillment GROUP BY customer_id ) -- Final output SELECT customer_id, fulfillment_rate FROM CustomerFulfillment;

Let's break down each part of the query step-by-step, explaining the logic and showcasing intermediate results.

Step 1: Calculate Fulfillment Rate for Each Order (OrderFulfillment CTE)

Determine the fulfillment rate for each individual order by calculating the ratio of delivered deliveries to total delivery attempts. If an order has no delivery attempts, its fulfillment rate is set to 0.

SQL:

WITH OrderFulfillment AS ( -- Calculate the fulfillment rate for each order SELECT o.order_id, o.customer_id, IFNULL(SUM(CASE WHEN d.status = 'delivered' THEN 1 ELSE 0 END) / COUNT(d.order_id), 0) AS fulfillment_rate FROM Orders o LEFT JOIN Deliveries d ON o.order_id = d.order_id GROUP BY o.order_id, o.customer_id )

Explanation:

  • SELECT o.order_id, o.customer_id:

    • Retrieves the order_id and customer_id from the Orders table.
  • LEFT JOIN Deliveries d ON o.order_id = d.order_id:

    • Performs a left join to include all orders, even those without any corresponding deliveries. This ensures that orders with no delivery attempts are accounted for.
  • SUM(CASE WHEN d.status = 'delivered' THEN 1 ELSE 0 END):

    • Counts the number of 'delivered' statuses for each order by summing up 1 for each 'delivered' delivery and 0 otherwise.
  • COUNT(d.order_id):

    • Counts the total number of delivery attempts for each order. This includes both 'delivered' and 'failed' statuses.
  • IFNULL(..., 0) AS fulfillment_rate:

    • Calculates the fulfillment rate by dividing the number of delivered deliveries by the total delivery attempts.
    • If there are no delivery attempts (COUNT(d.order_id) is 0), the fulfillment rate is set to 0 to avoid division by zero.
  • GROUP BY o.order_id, o.customer_id:

    • Groups the results by order_id and customer_id to perform the aggregations per order.

Intermediate Output After Step 1:

+----------+-------------+-----------------+ | order_id | customer_id | fulfillment_rate| +----------+-------------+-----------------+ | 1 | 100 | 0.50 | -- (1 delivered / 2 attempts) | 2 | 200 | 1.00 | -- (1 delivered / 1 attempt) | 3 | 100 | 1.00 | -- (2 delivered / 2 attempts) | 4 | 300 | 0.00 | -- (0 delivered / 1 attempt) +----------+-------------+-----------------+

Step 2: Aggregate Fulfillment Rate for Each Customer (CustomerFulfillment CTE)

Compute the fulfillment rate for each customer by averaging the fulfillment rates of all their orders. The result is rounded to two decimal places for precision.

SQL:

CustomerFulfillment AS ( -- Aggregate the fulfillment rate for each customer SELECT customer_id, ROUND(AVG(fulfillment_rate), 2) AS fulfillment_rate FROM OrderFulfillment GROUP BY customer_id )

Explanation:

  • SELECT customer_id, ROUND(AVG(fulfillment_rate), 2) AS fulfillment_rate:

    • For each customer_id, calculates the average fulfillment rate across all their orders.
    • The ROUND function ensures that the fulfillment rate is rounded to two decimal places.
  • FROM OrderFulfillment:

    • Utilizes the results from the OrderFulfillment CTE.
  • GROUP BY customer_id:

    • Groups the data by customer_id to perform the aggregation per customer.

Intermediate Output After Step 2:

+-------------+-------------------+ | customer_id | fulfillment_rate | +-------------+-------------------+ | 100 | 0.75 | | 200 | 1.00 | | 300 | 0.00 | +-------------+-------------------+

Explanation of Intermediate Output:

  • Customer 100:

    • Order 1: 0.50
    • Order 3: 1.00
    • Average Fulfillment Rate: (0.50 + 1.00) / 2 = 0.75
  • Customer 200:

    • Order 2: 1.00
    • Average Fulfillment Rate: 1.00 / 1 = 1.00
  • Customer 300:

    • Order 4: 0.00
    • Average Fulfillment Rate: 0.00 / 1 = 0.00

Step 3: Retrieve the Final Results

Select the customer_id and their corresponding fulfillment_rate from the CustomerFulfillment CTE to present the final results.

SQL Snippet:

-- Final output SELECT customer_id, fulfillment_rate FROM CustomerFulfillment;

Explanation:

  • SELECT customer_id, fulfillment_rate:

    • Retrieves each customer's ID and their calculated fulfillment rate.
  • FROM CustomerFulfillment:

    • Uses the aggregated data from the CustomerFulfillment CTE.

Final Output:

Based on the previous steps, the final output would be:

+-------------+-------------------+ | customer_id | fulfillment_rate | +-------------+-------------------+ | 100 | 0.75 | | 200 | 1.00 | | 300 | 0.00 | +-------------+-------------------+

.....

.....

.....

Like the course? Get enrolled and start learning!

On this page

Problem Statement

Example

Try It Yourself

Solution

Approach Overview

SQL Query

Step 1: Calculate Fulfillment Rate for Each Order (OrderFulfillment CTE)

Step 2: Aggregate Fulfillment Rate for Each Customer (CustomerFulfillment CTE)

Step 3: Retrieve the Final Results