ShopX
E-commerce (Amazon-style)
ShopX is an online marketplace selling electronics, fashion, home and grocery products to customers in several countries. As a data analyst at ShopX you answer questions from the product, finance and operations teams: who buys, what sells, which payments fail and which carriers deliver late. The schema has the tables you meet in real e-commerce interviews: customers, orders, order items, payments, shipments and reviews.
See the ShopX tables
ShopX schema
All tables live in the shopx schema, so write shopx.customers in your queries.
shopx.customers
One row per registered customer.
customer_id(INT) — PKfirst_name(VARCHAR(50))last_name(VARCHAR(50))email(VARCHAR(120))country(VARCHAR(50))signup_date(DATE)is_premium(BOOLEAN) — true for paid membership
shopx.customer_addresses
Saved delivery addresses; a customer can have several.
address_id(INT) — PKcustomer_id(INT) — FK → customers.customer_idaddress_line1(VARCHAR(120))city(VARCHAR(60))state(VARCHAR(60))postal_code(VARCHAR(12))country(VARCHAR(50))is_default(BOOLEAN)
shopx.product_categories
Category tree. Top-level categories have no parent.
category_id(INT) — PKcategory_name(VARCHAR(60))parent_category_id(INT) — FK → product_categories.category_id; nullable; NULL for a top-level category
shopx.products
The product catalogue.
product_id(INT) — PKproduct_name(VARCHAR(120))category_id(INT) — FK → product_categories.category_idprice(DECIMAL(10,2)) — current list priceis_active(BOOLEAN)created_at(DATE)
shopx.orders
One row per order (the order header).
order_id(INT) — PKcustomer_id(INT) — FK → customers.customer_idorder_date(DATE)order_status(VARCHAR(20)) — 'placed', 'shipped', 'delivered', 'cancelled', 'returned'total_amount(DECIMAL(12,2)) — amount charged for the whole order
shopx.order_items
Line items: one row per product in an order.
order_item_id(INT) — PKorder_id(INT) — FK → orders.order_idproduct_id(INT) — FK → products.product_idquantity(INT)unit_price(DECIMAL(10,2)) — price at the time of the orderdiscount_amount(DECIMAL(10,2)) — nullable; discount on the whole line; NULL when none
shopx.payments
Payment attempts. An order can have several attempts (e.g. a failed card, then a successful UPI payment).
payment_id(INT) — PKorder_id(INT) — FK → orders.order_idpayment_method(VARCHAR(20)) — 'card', 'upi', 'wallet', 'cod'payment_status(VARCHAR(20)) — 'success', 'failed', 'refunded'amount(DECIMAL(12,2))paid_at(TIMESTAMP)
shopx.shipments
One shipment per shipped order.
shipment_id(INT) — PKorder_id(INT) — FK → orders.order_idcarrier(VARCHAR(40))tracking_number(VARCHAR(40))shipped_at(TIMESTAMP)delivered_at(TIMESTAMP) — nullable; NULL while still in transit
shopx.product_reviews
Customer reviews of products.
review_id(INT) — PKproduct_id(INT) — FK → products.product_idcustomer_id(INT) — FK → customers.customer_idrating(INT) — 1 to 5review_title(VARCHAR(120))review_text(TEXT) — nullablereview_date(DATE)
Beginner (15)
- BeginnerBasic customer listOpen now
- BeginnerDistinct countriesOpen now
- BeginnerCustomer countOpen now
- BeginnerPremium customersOpen now
- BeginnerLow-price productsOpen now
- BeginnerMost expensive productsOpen now
- BeginnerOrders by statusOpen now
- BeginnerOrders in the last 90 days
- BeginnerOrder history for one customer
- Beginner5-star reviews
- BeginnerShipped orders count
- BeginnerAverage product price
- BeginnerCategory list with parent names
- BeginnerCustomers who signed up in the last 12 months
- BeginnerReview counts by rating
Intermediate (15)
- IntermediateTotal revenue from completed orders
- IntermediateCustomers with at least 10 orders
- IntermediateRevenue by countryOpen now
- IntermediateTop products by quantity sold
- IntermediateTop products by revenue
- IntermediatePayment success rate by method
- IntermediateCustomers with no ordersOpen now
- IntermediateAverage order value per month
- IntermediateAverage rating per product (min 20 reviews)
- IntermediateOrders with no successful payment
- IntermediateOrders per status per month
- IntermediateCustomers with more than one address
- IntermediateProducts and average price per category
- IntermediateActive customers in the last 90 days
- IntermediateLate deliveries (more than 7 days)
Advanced (28)
- AdvancedRank customers by total spend
- AdvancedTop 3 products per category by revenueOpen now
- AdvancedEach customer's first order
- AdvancedMonthly revenue with month-over-month growth
- Advanced7-day rolling revenue
- AdvancedTop 10% of customers by spend
- AdvancedBest-sellers with poor ratings
- AdvancedCustomer repeat rate
- AdvancedData quality: order totals that don't match
- AdvancedMonthly cohort revenue
- AdvancedDays from signup to first purchase
- AdvancedRFM metrics and scores
- AdvancedOn-time delivery rate by carrier
- AdvancedLapsed customers (no orders in 6 months)
- AdvancedHighest-spending customer in each country
- AdvancedThird distinct active-product price
- AdvancedCustomers who bought from every root category
- AdvancedReadable category paths with cycle protection
- AdvancedFrequently co-purchased product pairs
- AdvancedDelivered buyers minus refunded buyers
- AdvancedStable keyset pagination for an order history API
- AdvancedCalendar-based revenue average including zero-sales days
- AdvancedCanonical email collisions before a unique constraint
- AdvancedOne JSON line-item array per order
- AdvancedCompare-and-set order status transition
- AdvancedRead a sargable date-range query plan
- AdvancedBind hostile input as data, not SQL
- AdvancedCreate a reusable reporting view without confusing it with a snapshot
Mock interview round (10)
- IntermediateMock round 1: Revenue this year
- IntermediateMock round 2: New vs returning buyers (last 30 days)
- IntermediateMock round 3: Top 5 categories (last 90 days)
- IntermediateMock round 4: How much revenue is discounted?
- IntermediateMock round 5: Money stuck in failed payments
- IntermediateMock round 6: SLA breaches by carrier
- IntermediateMock round 7: Second order within 30 days
- IntermediateMock round 8: Low-rated best-sellers
- IntermediateMock round 9: Churn rate (9-month rule)
- IntermediateMock round 10: Country health summary