Basic Query Practice — Guided Walkthrough¶
Now that you know SELECT, WHERE, ORDER BY, LIMIT, and DISTINCT, it's time to combine them on a realistic dataset. This session walks through increasingly complex business questions — each one answered with a query you can run right now.
Sample Dataset¶
The queries in this file use three tables. Create them in your SQL environment before starting.
-- Customers table
CREATE TABLE customers (
customer_id VARCHAR(10) PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
email VARCHAR(100),
city VARCHAR(50),
country VARCHAR(50),
signup_date DATE,
segment VARCHAR(20) -- 'VIP', 'Regular', 'New'
);
-- Products table
CREATE TABLE products (
product_id VARCHAR(10) PRIMARY KEY,
product_name VARCHAR(100),
category VARCHAR(50),
unit_price DECIMAL(10,2),
cost_price DECIMAL(10,2),
stock_qty INT
);
-- Orders table
CREATE TABLE orders (
order_id VARCHAR(10) PRIMARY KEY,
customer_id VARCHAR(10),
product_id VARCHAR(10),
order_date DATE,
quantity INT,
unit_price DECIMAL(10,2),
discount_pct DECIMAL(5,2), -- can be NULL
status VARCHAR(20), -- 'completed', 'pending', 'cancelled', 'refunded'
delivery_date DATE -- NULL if not yet delivered
);
Sample data (insert to follow along)¶
INSERT INTO customers VALUES
('C001','Priya','Sharma','priya@gmail.com','Mumbai','India','2022-03-15','VIP'),
('C002','Arjun','Mehta','arjun@company.com','Delhi','India','2023-01-08','Regular'),
('C003','Sarah','Johnson','sarah@gmail.com','London','UK','2022-11-20','VIP'),
('C004','Liu','Wei','liu.wei@corp.com','Shanghai','China','2023-06-01','New'),
('C005','James','O''Brien','james@outlook.com','Dublin','Ireland','2022-07-14','Regular');
INSERT INTO products VALUES
('P001','Wireless Headphones','Electronics',149.00,65.00,45),
('P002','Yoga Mat','Sports',35.99,12.00,200),
('P003','Data Analytics Book','Books',49.99,18.00,80),
('P004','Standing Desk','Furniture',389.00,180.00,12),
('P005','Coffee Maker','Kitchen',89.99,35.00,67);
INSERT INTO orders VALUES
('O001','C001','P001','2024-01-05',2,149.00,NULL,'completed','2024-01-08'),
('O002','C003','P004','2024-01-07',1,389.00,10.00,'completed','2024-01-12'),
('O003','C002','P003','2024-01-09',3,49.99,NULL,'pending',NULL),
('O004','C001','P002','2024-01-10',1,35.99,5.00,'completed','2024-01-13'),
('O005','C004','P001','2024-01-11',1,149.00,NULL,'cancelled',NULL),
('O006','C005','P005','2024-01-14',2,89.99,15.00,'completed','2024-01-18'),
('O007','C003','P003','2024-01-15',5,49.99,NULL,'pending',NULL),
('O008','C002','P004','2024-01-18',1,389.00,NULL,'pending',NULL);
Guided Business Questions¶
Q1 — What products do we sell?¶
Output:
| product_id | product_name | category | unit_price |
|---|---|---|---|
| P003 | Data Analytics Book | Books | 49.99 |
| P001 | Wireless Headphones | Electronics | 149.00 |
| P004 | Standing Desk | Furniture | 389.00 |
| P005 | Coffee Maker | Kitchen | 89.99 |
| P002 | Yoga Mat | Sports | 35.99 |
Q2 — Which orders are still pending delivery?¶
SELECT
order_id,
customer_id,
product_id,
order_date,
status
FROM orders
WHERE delivery_date IS NULL
AND status <> 'cancelled'
ORDER BY order_date;
Output:
| order_id | customer_id | product_id | order_date | status |
|---|---|---|---|---|
| O003 | C002 | P003 | 2024-01-09 | pending |
| O007 | C003 | P003 | 2024-01-15 | pending |
| O008 | C002 | P004 | 2024-01-18 | pending |
Q3 — What is the order total for each order?¶
Note: we need to account for the optional discount.
SELECT
order_id,
customer_id,
quantity,
unit_price,
discount_pct,
quantity * unit_price AS gross_total,
quantity * unit_price * (1 - COALESCE(discount_pct, 0) / 100) AS net_total
FROM orders
ORDER BY net_total DESC;
Output:
| order_id | customer_id | quantity | unit_price | discount_pct | gross_total | net_total |
|---|---|---|---|---|---|---|
| O002 | C003 | 1 | 389.00 | 10.00 | 389.00 | 350.10 |
| O008 | C002 | 1 | 389.00 | NULL | 389.00 | 389.00 |
| O001 | C001 | 2 | 149.00 | NULL | 298.00 | 298.00 |
COALESCE explained
COALESCE(discount_pct, 0) returns discount_pct if it's not NULL, or 0 if it is. This means "treat no discount as 0% off."
Q4 — Which VIP customers placed orders this month?¶
SELECT DISTINCT
o.customer_id,
c.first_name,
c.last_name,
c.segment
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE c.segment = 'VIP'
AND o.order_date >= '2024-01-01'
ORDER BY c.last_name;
Output:
| customer_id | first_name | last_name | segment |
|---|---|---|---|
| C003 | Sarah | Johnson | VIP |
| C001 | Priya | Sharma | VIP |
We're previewing JOINs here
We need data from two tables — orders (for dates) and customers (for segment). JOINs are covered fully in Week-01/Day-02-Part-2-SQL-Advanced/01-joins.
Q5 — What categories of products have we sold?¶
SELECT DISTINCT
p.category
FROM orders o
JOIN products p ON o.product_id = p.product_id
WHERE o.status = 'completed'
ORDER BY p.category;
Output:
| category |
|---|
| Books |
| Electronics |
| Furniture |
| Kitchen |
| Sports |
Q6 — Top 3 most ordered products¶
SELECT
product_id,
COUNT(*) AS times_ordered,
SUM(quantity) AS total_units_sold
FROM orders
WHERE status = 'completed'
GROUP BY product_id
ORDER BY total_units_sold DESC
LIMIT 3;
Output:
| product_id | times_ordered | total_units_sold |
|---|---|---|
| P003 | 2 | 8 |
| P001 | 1 | 2 |
| P002 | 1 | 1 |
GROUP BY preview
We're previewing GROUP BY and aggregate functions here — they're covered fully in Week-01/Day-02-Part-2-SQL-Advanced/02-group-by-and-having.
Common Query Patterns to Memorise¶
-- Preview a new table safely
SELECT * FROM table_name LIMIT 100;
-- Unique values in a column
SELECT DISTINCT column_name FROM table_name ORDER BY column_name;
-- Filter + sort + limit (Top N)
SELECT cols FROM table WHERE condition ORDER BY metric DESC LIMIT n;
-- Count unique values
SELECT COUNT(DISTINCT column_name) FROM table_name;
-- Null check
SELECT * FROM table WHERE column IS NULL;
SELECT * FROM table WHERE column IS NOT NULL;
Checklist Before Running Any Query¶
Before you hit run, ask yourself:
- [ ] Did I specify only the columns I need (not
SELECT *)? - [ ] Does my
WHEREclause narrow down the rows correctly? - [ ] If filtering dates, did I use
BETWEENor>=/<=correctly? - [ ] Did I handle NULL values with
IS NULL/IS NOT NULL? - [ ] Did I add
LIMITif this is an exploratory query on a large table? - [ ] Does the
ORDER BYmatch what the question is asking for?