SQL Interview Prep - Day 7

Zomato Swapped Food Delivery

Correcting Order Swapping Errors in Zomato's Delivery System Using SQL

In the world of online food delivery, accuracy is paramount—whether it’s getting the right food to the right customer or ensuring that the order data is properly organized. But what happens when a technical glitch causes a mix-up in order data? This is exactly the scenario faced by Zomato, a leading food delivery platform, where due to an error in their delivery system, each food item’s order ID was swapped with the next one.

As a data analyst, your task is to identify the customers’ orders, fix this error, and return the correct order IDs and their associated items. But here’s the catch: the dataset contains a unique requirement: if the last item in the dataset has an odd order_id, it should remain unchanged.

In this blog, we'll walk through a SQL-based solution to correct this order data by leveraging the power of window functions, specifically the ROW_NUMBER() function. Let's dive into how we can achieve this.


Understanding the Problem

Given a table that contains orders and their corresponding food items, the order IDs have been incorrectly swapped. For instance, order_id 1 might be associated with "Chow Mein," but the system mistakenly swapped it with order_id 2, which should have been associated with "Pizza." Our goal is to retrieve the correct pairs of order_id and item, ensuring the last item remains unchanged if its order_id is odd.

Input Data:

order_iditem
1Chow Mein
2Pizza
3Pad Thai
4Butter Chicken
5Eggrolls
6Burger
7Tandoori Chicken

Expected Output:

corrected_order_iditem
1Pizza
2Chow Mein
3Butter Chicken
4Pad Thai
5Burger
6Eggrolls
7Tandoori Chicken

In the corrected output, you’ll notice that:

  • The odd-numbered order IDs are paired correctly with the next even-numbered rows.

  • The last row (with order_id 7) remains unchanged since it has an odd order_id.


The Solution

We can solve this problem using a combination of SQL features, particularly window functions. Let’s break down the solution step by step.

Step 1: Using ROW_NUMBER() to Track Row Positions

The first task is to assign a unique sequential number to each row. This will help us track the position of each row and determine whether it’s an odd or even-numbered row.

We can achieve this using the ROW_NUMBER() window function, which assigns an integer to each row, ordered by the order_id.

WITH NumberedOrders AS (
    SELECT 
        order_id,
        item,
        ROW_NUMBER() OVER (ORDER BY order_id) AS rn
    FROM orders
)

Here:

  • ROW_NUMBER() OVER (ORDER BY order_id) generates a sequential row number (rn) for each row in the table, ordered by the order_id.

  • The result is a temporary table (NumberedOrders) with the order_id, item, and a new column rn that tracks the row’s position.

Step 2: Swap Logic Using CASE

Now that we have a row number for each record, we can use the CASE statement to swap the rows. The logic is simple:

  • For odd-numbered rows (rn % 2 = 1), swap with the next row (rn + 1).

  • For even-numbered rows (rn % 2 = 0), swap with the previous row (rn - 1).

  • For the last row, if it has an odd order_id, leave it as is.

Here’s the SQL query implementing this logic:

SELECT
    CASE 
        -- For odd rows, swap with the next row
        WHEN rn % 2 = 1 AND rn + 1 <= (SELECT COUNT(*) FROM orders) THEN
            (SELECT order_id FROM NumberedOrders WHERE rn = o.rn + 1)

        -- For even rows, swap with the previous row
        WHEN rn % 2 = 0 THEN
            (SELECT order_id FROM NumberedOrders WHERE rn = o.rn - 1)

        -- For the last row with an odd order_id, leave it unchanged
        ELSE 
            o.order_id
    END AS corrected_order_id,

    CASE 
        -- For odd rows, swap with the next row
        WHEN rn % 2 = 1 AND rn + 1 <= (SELECT COUNT(*) FROM orders) THEN
            (SELECT item FROM NumberedOrders WHERE rn = o.rn + 1)

        -- For even rows, swap with the previous row
        WHEN rn % 2 = 0 THEN
            (SELECT item FROM NumberedOrders WHERE rn = o.rn - 1)

        -- For the last row with an odd order_id, leave it unchanged
        ELSE 
            o.item
    END AS item
FROM NumberedOrders o;

Explanation of the Query:

  • NumberedOrders CTE:

    • We first generate a temporary table with order_id, item, and a sequential rn (row number) using ROW_NUMBER().
  • CASE Statement:

    • For odd rn, we fetch the values of the next row (rn + 1), which "fixes" the swap.

    • For even rn, we fetch the values of the previous row (rn - 1).

    • The ELSE clause ensures that the last row (if it has an odd order_id) stays unchanged.

Final Output:

After running this query, we will get the corrected order IDs and items, with the data displayed in the correct pairing order, as shown below:

corrected_order_iditem
1Pizza
2Chow Mein
3Butter Chicken
4Pad Thai
5Burger
6Eggrolls
7Tandoori Chicken

Conclusion

By using SQL’s ROW_NUMBER() function in combination with CASE statements, we can easily fix a situation where rows have been incorrectly swapped, without modifying the underlying data in the database. This approach ensures:

  • No data modification: We simply adjust how the data is retrieved, not how it’s stored.

  • Efficient and dynamic swapping: The ROW_NUMBER() function allows us to track row positions and swap rows based on their sequential order.

  • Handles edge cases: The logic ensures that the last row, if it has an odd order_id, remains unchanged.

With this method, Zomato's data can be quickly and accurately corrected, restoring the integrity of the order information without any manual intervention or database updates. This is a great example of how SQL can be used to solve real-world data issues in a dynamic and efficient manner.


I hope you found this article helpful in understanding how to solve such data issues with SQL! Stay tuned for more insights on how to use SQL to solve common data problems.

Happy Querying 🔥🚀