You don't need to memorise SQL. You need the 30 patterns that keep coming back.
Part 1 is the 10 queries you write every week. Part 2 answers the 20 questions you end up Googling: duplicates, 2nd highest salary, top 3 per group, month-on-month change.
Save it. Use it weekly.
10 queries you write every week
- 01
WHERE
SELECT * FROM orders WHERE amount > 500; - 02
ORDER BY + LIMIT
SELECT * FROM orders ORDER BY amount DESC LIMIT 5; - 03
GROUP BY
SELECT city, COUNT(*) FROM users GROUP BY city; - 04
HAVING
SELECT city, COUNT(*) FROM users GROUP BY city HAVING COUNT(*) > 10; - 05
JOIN
SELECT * FROM orders o JOIN users u ON o.user_id = u.id; - 06
DISTINCT
SELECT DISTINCT city FROM users; - 07
COALESCE
SELECT COALESCE(phone, 'NA') FROM users; - 08
CASE WHEN
CASE WHEN amount > 1000 THEN 'High' ELSE 'Low' END - 09
RANK()
RANK() OVER (ORDER BY salary DESC) - 10
Running total
SUM(amount) OVER (ORDER BY order_date)
SQL: how do I …
- 01
Count unique customers
COUNT(DISTINCT customer_id) - 02
Find customers who never ordered
LEFT JOIN orders o ON o.user_id = u.id WHERE o.id IS NULL - 03
Find duplicate emails
GROUP BY email HAVING COUNT(*) > 1 - 04
Get the 2nd highest salary
DENSE_RANK() OVER (ORDER BY salary DESC) -- keep rank 2 - 05
Top 3 per department
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) <= 3 -- filter in outer query - 06
Previous month's value
LAG(sales) OVER (ORDER BY month) - 07
Month-on-month change
sales - LAG(sales) OVER (ORDER BY month) - 08
Search text in a column
WHERE name LIKE '%kumar%' - 09
Match a list of values
WHERE city IN ('Pune', 'Indore') - 10
Filter a date range
WHERE dt >= '2026-01-01' AND dt < '2026-04-01' - 11
Replace NULL with 0
COALESCE(amount, 0) - 12
Avoid divide by zero
amount / NULLIF(qty, 0) - 13
Pull the year from a date
EXTRACT(YEAR FROM order_date) - 14
Join two text columns
CONCAT(first_name, ' ', last_name) - 15
Stack two tables
UNION ALL -- keeps duplicates - 16
Check if related rows exist
WHERE EXISTS (SELECT 1 FROM ...) - 17
Reuse a subquery
WITH t AS (SELECT ...) SELECT * FROM t - 18
Percent of total
amount * 100.0 / SUM(amount) OVER () - 19
Round to 2 decimals
ROUND(avg_price, 2) - 20
Count with a condition
SUM(CASE WHEN status = 'Paid' THEN 1 ELSE 0 END)
Window functions (RANK, ROW_NUMBER, LAG) can't go in WHERE. Wrap them in a subquery or CTE, then filter.
Now type them yourself
Reading isn't practice. Run these on real tables in the free SQL playground. Your answer gets checked instantly.