Can you really learn SQL in 30 days?
Yes, if "learn" means you can answer business questions with SELECT, GROUP BY, joins, CTEs and basic window functions. That is the level most data analyst screening tests check. It will not make you a database administrator, and fluency keeps growing for months after.
The plan below assumes about 1 to 1.5 hours a day, six days a week, with day 7 of each week kept for review. If you have less time, stretch it to 45 days rather than skipping days. Consistency matters more than long weekend sessions.
If you are still deciding whether to take a course instead, our guide on how to choose a SQL course in India compares free and paid options.
Which free tools do you need to learn SQL?
You need one place to run queries. Pick one and stay with it for the full 30 days. The core SQL you learn works across all of them, with small differences in date functions.
| Tool | Cost (checked September 2026) | Good for | Watch out for |
|---|---|---|---|
| SQLite + DB Browser for SQLite | Free, open source | Fastest setup on Windows, macOS or Linux; one file holds the whole database | Date functions differ from PostgreSQL (strftime instead of DATE_TRUNC) |
| PostgreSQL | Free, open source (PostgreSQL License) | The same engine many companies run; closest to job work | Installation takes longer; use pgAdmin or DBeaver as the editor |
| Google BigQuery sandbox | Free, no credit card; 10 GiB storage and 1 TiB of queries a month | Querying large public datasets in the browser | Tables expire after 60 days in the sandbox |
| Kaggle Learn (Intro to SQL, Advanced SQL) | Free | Short guided lessons with exercises | Uses BigQuery syntax; add your own practice alongside |
Our suggestion for most beginners: SQLite with DB Browser for SQLite for weeks 1 to 3, then try the same queries in PostgreSQL or BigQuery in week 4. SQLite has supported window functions since version 3.25.0, so every query in this plan runs on it.
What practice dataset should you use?
Use a small dataset first, so you can check every answer by eye. The script below creates an online shop with 8 customers and 14 orders. Paste it into the "Execute SQL" tab of DB Browser for SQLite (or psql) and run it once.
CREATE TABLE customers (
customer_id INTEGER PRIMARY KEY,
name TEXT,
city TEXT,
signup_date TEXT
);
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER,
order_date TEXT,
category TEXT,
amount INTEGER,
status TEXT
);
INSERT INTO customers VALUES
(1,'Aarav','Bengaluru','2026-01-05'), (2,'Diya','Mumbai','2026-01-12'),
(3,'Kabir','Pune','2026-01-20'), (4,'Meera','Bengaluru','2026-02-03'),
(5,'Rohan','Delhi','2026-02-14'), (6,'Sana','Mumbai','2026-02-25'),
(7,'Vikram','Pune','2026-03-02'), (8,'Isha','Delhi','2026-03-18');
INSERT INTO orders VALUES
(101,1,'2026-01-06','Electronics',4500,'delivered'),
(102,2,'2026-01-15','Fashion',1200,'delivered'),
(103,1,'2026-01-28','Grocery',800,'delivered'),
(104,3,'2026-02-02','Electronics',6200,'returned'),
(105,4,'2026-02-05','Fashion',2100,'delivered'),
(106,2,'2026-02-10','Grocery',650,'delivered'),
(107,5,'2026-02-16','Electronics',3900,'delivered'),
(108,1,'2026-02-20','Fashion',1500,'delivered'),
(109,6,'2026-03-01','Grocery',900,'cancelled'),
(110,4,'2026-03-04','Electronics',5200,'delivered'),
(111,7,'2026-03-05','Fashion',1800,'delivered'),
(112,5,'2026-03-12','Grocery',700,'delivered'),
(113,2,'2026-03-20','Electronics',7400,'delivered'),
(114,3,'2026-03-25','Grocery',550,'delivered');
The names and numbers are made up for practice. From week 3 onwards, add a bigger public dataset too, such as an e-commerce or sales dataset from Kaggle, or a BigQuery public dataset. Real data brings nulls, duplicates and odd dates, which is where most learning happens.
Week 1 (days 1–7): How do you read data with SELECT?
| Day | Topic | Task on the shop data |
|---|---|---|
| 1 | Set up tool; SELECT, FROM, LIMIT | Create the tables; show the first 5 orders |
| 2 | WHERE with =, >, <, AND, OR | List delivered orders above ₹3,000 |
| 3 | IN, BETWEEN, LIKE | Orders in Fashion or Grocery placed in February |
| 4 | ORDER BY, DISTINCT, aliases | List each city once, alphabetically |
| 5 | NULL, IS NULL, COALESCE | Insert an order with no category and find it |
| 6 | Calculated columns and CASE WHEN | Label orders as "high" (≥ ₹3,000) or "low" |
| 7 | Review | Solve 10 easy problems on HackerRank or SQLBolt without notes |
Day 2 on the sample data looks like this:
SELECT order_id, customer_id, amount
FROM orders
WHERE status = 'delivered' AND amount > 3000
ORDER BY amount DESC;
Expected output: 4 rows, orders 113 (₹7,400), 110 (₹5,200), 101 (₹4,500) and 107 (₹3,900). Order 104 is ₹6,200 but was returned, so it is correctly left out.
Week 1 milestone: you can filter and sort any single table and explain each line of your query.
Want feedback on your SQL, not just answers?
The ISS Data & Business Intelligence program spends weeks 3 and 4 on SQL, from PostgreSQL basics to joins, CTEs, window functions and cohort analysis, with live weekend sessions. Compare it with this self-study plan, and grab the free Data Analyst Starter Kit on this page for project briefs and interview questions.
View Data & Business Intelligence curriculum →Week 2 (days 8–14): How do GROUP BY and joins work?
This is the week that turns lists into answers. Most business questions are "how many" or "how much" by some group, and most real data sits in more than one table.
| Day | Topic | Task on the shop data |
|---|---|---|
| 8 | COUNT, SUM, AVG, MIN, MAX | Average order value of delivered orders (answer: ₹2,525 over 12 orders) |
| 9 | GROUP BY | Orders and revenue by category |
| 10 | HAVING vs WHERE | Categories with more than 4 orders |
| 11 | INNER JOIN | Delivered revenue by city |
| 12 | LEFT JOIN and finding missing rows | Customers who never ordered |
| 13 | Joins that duplicate rows; counting correctly | Compare COUNT(*) and COUNT(DISTINCT customer_id) |
| 14 | Review | 10 medium problems; write down every mistake |
Day 11, delivered revenue by city:
SELECT c.city,
COUNT(o.order_id) AS orders,
SUM(o.amount) AS revenue
FROM orders o
JOIN customers c ON c.customer_id = o.customer_id
WHERE o.status = 'delivered'
GROUP BY c.city
ORDER BY revenue DESC;
Expected output:
| city | orders | revenue |
|---|---|---|
| Bengaluru | 5 | 14100 |
| Mumbai | 3 | 9250 |
| Delhi | 2 | 4600 |
| Pune | 2 | 2350 |
Day 12 uses a LEFT JOIN to find customers with no orders at all. On this data it returns one row: Isha from Delhi.
SELECT c.name, c.city
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
WHERE o.order_id IS NULL;
If joins feel shaky, read our SQL joins explained guide before moving on. Week 2 milestone: you can build a summary table from two joined tables and check that the row count makes sense.
Week 3 (days 15–21): When do you use subqueries, CTEs and dates?
| Day | Topic | Task |
|---|---|---|
| 15 | Subqueries in WHERE | Orders above the average order value |
| 16 | Subqueries in FROM | Revenue per customer, then the average of that |
| 17 | CTEs with WITH | Rewrite day 16 as a CTE and compare readability |
| 18 | Date functions | Monthly delivered revenue (strftime('%Y-%m', …) in SQLite, DATE_TRUNC in PostgreSQL) |
| 19 | String functions and cleaning | Trim, upper-case and fix messy city names in a public dataset |
| 20 | Load a bigger public dataset | Import a CSV and profile it: rows, nulls, duplicates, date range |
| 21 | Review | Answer 5 questions of your own on the bigger dataset |
A CTE for repeat-purchase rate shows why CTEs matter. Each step has a name, so a reviewer can follow it:
WITH per_customer AS (
SELECT customer_id, COUNT(*) AS delivered_orders
FROM orders
WHERE status = 'delivered'
GROUP BY customer_id
)
SELECT COUNT(*) AS buyers,
SUM(CASE WHEN delivered_orders >= 2 THEN 1 ELSE 0 END) AS repeat_buyers,
ROUND(100.0 * SUM(CASE WHEN delivered_orders >= 2 THEN 1 ELSE 0 END)
/ COUNT(*), 1) AS repeat_rate_pct
FROM per_customer;
Expected output: 6 buyers, 4 repeat buyers, a repeat rate of 66.7%. Note the 100.0: with plain 100, integer division in SQLite and PostgreSQL would give the wrong answer.
Week 3 milestone: you can break a question into named steps and produce a monthly trend from raw dates.
Week 4 (days 22–30): How do window functions help, and what is the final project?
| Day | Topic | Task |
|---|---|---|
| 22 | ROW_NUMBER and PARTITION BY | Each customer's first order |
| 23 | RANK and DENSE_RANK | Top category by revenue in each city |
| 24 | LAG and LEAD | Month-on-month revenue growth |
| 25 | Running totals | Cumulative revenue by date |
| 26–29 | Final project | See the brief below |
| 30 | Write-up and mock test | Publish the project; take a timed 30-minute test |
Day 24, month-on-month growth with LAG:
WITH monthly AS (
SELECT strftime('%Y-%m', order_date) AS month,
SUM(amount) AS revenue
FROM orders
WHERE status = 'delivered'
GROUP BY month
)
SELECT month,
revenue,
LAG(revenue) OVER (ORDER BY month) AS prev_revenue,
ROUND(100.0 * (revenue - LAG(revenue) OVER (ORDER BY month))
/ LAG(revenue) OVER (ORDER BY month), 1) AS growth_pct
FROM monthly;
Expected output:
| month | revenue | prev_revenue | growth_pct |
|---|---|---|---|
| 2026-01 | 6500 | NULL | NULL |
| 2026-02 | 8150 | 6500 | 25.4 |
| 2026-03 | 15650 | 8150 | 92.0 |
In PostgreSQL, replace the strftime line with TO_CHAR(order_date::date, 'YYYY-MM'). The window part is identical.
What should the final SQL project look like?
Pick a public sales or e-commerce dataset with at least a few thousand rows and a date column. Then answer one business question end to end, for example: "Which customer segment should the marketing team focus on next quarter?"
- Profile the data: row counts, date range, nulls and duplicates, with the queries you used.
- Core metrics: monthly revenue, orders, average order value and repeat rate.
- Segments: the same metrics by city, category or customer type.
- One window-function insight: first-order category, month-on-month growth or top products per segment.
- Recommendation: three sentences on what the business should do, and what you would check next.
Put the queries in a GitHub repository with a short README that leads with the finding, not the code. Our guide to data analyst resume projects shows how to frame it for a recruiter.
What mistakes slow people down when learning SQL?
- Watching, not typing. Type every query yourself, even when you could copy it.
- Not checking row counts. After every join, check whether the number of rows went up unexpectedly.
- Filtering aggregates with WHERE. Use
HAVINGfor conditions onSUMorCOUNT. - Ignoring NULLs.
COUNT(column)skips NULLs;COUNT(*)does not. - Switching tools every week. Pick one database and finish the plan in it.
- Only solving puzzles. Practice sites are useful for speed, but interviews also ask you to explain what a result means for the business.
When you finish, test yourself against our list of SQL interview questions and the wider data analytics interview questions guide. For where SQL fits among Excel, BI tools and Python, see the data analyst roadmap.
Frequently Asked Questions
Can I learn SQL in 30 days with no coding background?
Yes. SQL reads close to plain English, and this plan starts from SELECT. At 1 to 1.5 hours a day, most beginners can reach joins, CTEs and basic window functions in 30 days. Expect to keep practising afterwards to get fast.
Which free tool should I use to learn SQL?
For most beginners, SQLite with DB Browser for SQLite is the quickest to set up, and it is free and open source. PostgreSQL is closer to what many companies run. The BigQuery sandbox is free without a credit card and suits large public datasets.
Is SQL enough to get a data analyst job?
Usually not on its own. Most analyst roles also ask for Excel, a BI tool such as Power BI or Tableau, and the ability to explain findings. SQL is the foundation that most screening tests check first.
Should I learn MySQL or PostgreSQL first?
Either is fine. SELECT, JOIN, GROUP BY, CTEs and window functions work the same way in both. Differences are mostly in date and string functions, which take a few days to adjust to.
How many hours a day should I practise SQL?
About 1 to 1.5 hours a day, six days a week, is enough for this plan. If you have less time, stretch the plan to 45 days instead of skipping topics.
What should I do after the 30 days?
Keep solving two or three problems a day, redo your final project on a larger dataset, and add a BI tool such as Power BI so you can present your SQL results as a dashboard.
Sources and methodology
Tool costs and limits were checked on official pages in September 2026.
- SQLite, Window Functions (support added in version 3.25.0), checked September 2026.
- DB Browser for SQLite (open source; Windows, macOS, Linux), checked September 2026.
- PostgreSQL, License, checked September 2026.
- Google Cloud, BigQuery sandbox (10 GiB storage, 1 TiB queries a month, 60-day table expiry, no credit card), checked September 2026.
- Kaggle, Intro to SQL and Advanced SQL; SQLBolt; HackerRank SQL. Free and paid tiers change; check each site.
- ISS: Data & Business Intelligence program page (SQL in weeks 3 and 4).
The shop dataset is made up for practice. Every query and expected output shown was run on it in SQLite 3.54 before publishing. The 30-day schedule and time estimates are ISS editorial guidance, not a provider's figures.
Next steps
Start day 1 today: install DB Browser for SQLite, paste the dataset script and run your first SELECT. If you would rather learn SQL alongside Excel, Python and dashboards in a live 16-week cohort, review the Data & Business Intelligence curriculum.
Applying is free, and you pay only after accepting an offer. Apply here.