Problem

Table: Delivery

+—————————–+———+ | Column Name | Type | +—————————–+———+ | delivery_id | int | | customer_id | int | | order_date | date | | customer_pref_delivery_date | date | +—————————–+———+ delivery_id is the column of unique values of this table. The table holds information about food delivery to customers that make orders at some date and specify a preferred delivery date (on the same order date or after it).

If the customer’s preferred delivery date is the same as the order date, then the order is called immediate; otherwise, it is called scheduled.

The first order of a customer is the order with the earliest order date that the customer made. It is guaranteed that a customer has precisely one first order.

Write a solution to find the percentage of immediate orders in the first orders of all customers, rounded to 2 decimal places.

Solution

Method 1 – Window Functions and Aggregation

Intuition

We want to find, for each customer, their first order and check if it was immediate (order date equals preferred delivery date). Then, we calculate the percentage of such immediate first orders among all customers.

Approach

  1. Use a window function (ROW_NUMBER) to identify the first order for each customer by ordering their orders by order_date.
  2. Filter to only the first order per customer.
  3. Count how many of these first orders are immediate (order_date = customer_pref_delivery_date).
  4. Calculate the percentage and round to 2 decimal places.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
SELECT
  ROUND(
    100.0 * SUM(order_date = customer_pref_delivery_date) / COUNT(*),
    2
  ) AS immediate_percentage
FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date) AS rn
  FROM Delivery
) t
WHERE rn = 1;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
SELECT
  ROUND(
    100.0 * SUM(CASE WHEN order_date = customer_pref_delivery_date THEN 1 ELSE 0 END) / COUNT(*),
    2
  ) AS immediate_percentage
FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date) AS rn
  FROM Delivery
) t
WHERE rn = 1;
1
2
3
4
5
6
def immediate_percentage(df: 'pd.DataFrame') -> float:
    df1 = df.sort_values(['customer_id', 'order_date'])
    first_orders = df1.groupby('customer_id', as_index=False).first()
    cnt = (first_orders['order_date'] == first_orders['customer_pref_delivery_date']).sum()
    ans = round(100.0 * cnt / len(first_orders), 2)
    return ans

Complexity

  • ⏰ Time complexity: O(n) — We scan all rows once to find first orders and count immediate ones.
  • 🧺 Space complexity: O(n) — We may need to store all rows for grouping and windowing.