Knowledge Guide
HomeDatabasesSQL Practice Problems

medium Order Fulfillment Rate

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

java
-- TODO: Write your user queries here

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:

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:

Intermediate Output After Step 2:

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

Explanation of Intermediate Output:

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:

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 | +-------------+-------------------+
🤖 Don't fully get this? Learn it with Claude

Stuck on Order Fulfillment Rate? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🪜 Hint ladder (no spoilers)

Progressively stronger hints — you still solve it.

I'm working on the problem **Order Fulfillment Rate** (Databases). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🎨 Explain the approach visually

See the technique, not just code.

Explain the optimal approach to **Order Fulfillment Rate** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔍 Review my solution

Catch bugs, edge cases, sub-optimality.

I'll paste my solution to **Order Fulfillment Rate**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔁 Drill the pattern

Lock in recognition with look-alikes.

Give me 2 problems that use the SAME underlying pattern as **Order Fulfillment Rate**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes