Quick Overview

This question evaluates proficiency with pandas-based data manipulation, including multi-table joins, aggregations, dtype enforcement, denormalization, and verification of row/column integrity within the Data Manipulation (SQL/Python) domain for a Data Scientist role.

Merge seven tables into one clean DataFrame

Company: Capital One

Role: Data Scientist

Category: Data Manipulation (SQL/Python)

Difficulty: medium

Interview Round: HR Screen

Using pandas only (no loops over rows), write a function build_facts(customers, orders, order_items, products, payments, shipments, refunds) -> pd.DataFrame that returns a single denormalized table with exactly these columns in this order: ["order_item_id","order_id","customer_id","order_ts","paid_ts","shipped_ts","product_id","sku","category","qty","unit_price","line_amount","refund_amount","country","status","payment_method","carrier"]. Input tables (columns): customers(customer_id:int, signup_date:datetime, country:str); orders(order_id:int, customer_id:int, order_ts:datetime, status:str); order_items(order_item_id:int, order_id:int, product_id:int, qty:int, unit_price:float); products(product_id:int, sku:str, category:str); payments(payment_id:int, order_id:int, paid_ts:datetime, method:str, amount:float); shipments(shipment_id:int, order_id:int, shipped_ts:datetime, carrier:str, ship_cost:float); refunds(refund_id:int, order_item_id:int, refund_ts:datetime, refund_amount:float, reason:str). Rules: one row per order_item_id; line_amount = qty * unit_price; refund_amount = sum of refund_amount per order_item_id (0.0 if none); paid_ts = max(paid_ts) per order; payment_method = method associated with the largest payment amount for the order (break ties by lexicographically smallest method); shipped_ts = earliest shipped_ts per order (NaT if none); left‑join so every order_item_id in order_items appears exactly once; ensure datetime dtypes for *_ts, numeric dtypes for qty/unit_price/line_amount/refund_amount; output must contain no extra or missing columns and exact lower_snake_case names. Provide brief unit‑test style assertions for row count preservation, sorted column order, and absence of duplicate order_item_id.

Overview: This question evaluates proficiency with pandas-based data manipulation, including multi-table joins, aggregations, dtype enforcement, denormalization, and verification of row/column integrity within the Data Manipulation (SQL/Python) domain for a Data Scientist role.

You are given seven PostgreSQL tables describing an e-commerce system: customers, orders, order_items, products, payments, shipments, and refunds. Write a single SQL query that returns a denormalized fact table with exactly these columns in this order: order_item_id, order_id, customer_id, order_ts, paid_ts, shipped_ts, product_id, sku, category, qty, unit_price, line_amount, refund_amount, country, status, payment_method, carrier Rules: - Return one row per order_item_id; every row from order_items must appear exactly once. - line_amount = qty * unit_price. - refund_amount = SUM(refund_amount) for that order_item_id; use 0.0 when there are no refunds. - paid_ts = the latest paid_ts per order_id; if an order has no payments, paid_ts is NULL. - payment_method = the method for the largest payment amount for that order_id; if multiple payments tie for largest amount, choose the lexicographically smallest method. If an order has no payments, payment_method is NULL. - shipped_ts = the earliest shipped_ts per order_id; if an order has no shipments, shipped_ts is NULL. - carrier = the carrier for that earliest shipment; if multiple shipments tie for earliest timestamp, choose the lexicographically smallest carrier. If an order has no shipments, carrier is NULL. - Use left joins for optional payments, shipments, and refunds so order_items are not dropped. - Format order_ts, paid_ts, and shipped_ts as YYYY-MM-DD HH24:MI:SS strings. Return the result ordered by order_item_id.

Tables

customers(customer_id INT, signup_date TIMESTAMP, country VARCHAR(2))

orders(order_id INT, customer_id INT, order_ts TIMESTAMP, status VARCHAR(20))

order_items(order_item_id INT, order_id INT, product_id INT, qty INT, unit_price DECIMAL(10,2))

products(product_id INT, sku VARCHAR(50), category VARCHAR(50))

payments(payment_id INT, order_id INT, paid_ts TIMESTAMP, method VARCHAR(30), amount DECIMAL(10,2))

shipments(shipment_id INT, order_id INT, shipped_ts TIMESTAMP, carrier VARCHAR(30), ship_cost DECIMAL(10,2))

refunds(refund_id INT, order_item_id INT, refund_ts TIMESTAMP, refund_amount DECIMAL(10,2), reason VARCHAR(100))

Hints

  1. Use ROW_NUMBER() to pick the largest payment amount per order with a method tiebreaker, and a window MAX() to retain the latest paid_ts.
  2. Use another ROW_NUMBER() to choose the earliest shipment per order with a carrier tiebreaker.

Loading coding console...