SQL: Ask Any Database Any Question
Query, filter, join and summarise data, and prove your answers are right, using one small practice database you build yourself.
One payment of $39. Instant online access to the full written course. No subscription. Refund policy.
You will be able to write SQL that answers business questions from a database: choose and sort columns, filter rows, summarise and group, join tables, and check that your numbers are right. You finish with a report you built and checked yourself.
Who it is for. Complete beginners with no coding background: office workers, aspiring analysts, business owners and career changers who want to answer questions from data instead of guessing.
You finish with. The Fernwood Business-Questions Report. You finish one SQL file, fernwood_report.sql, that answers ten business questions about the practice shop. Every entry has the question, the query, the pasted result and one honest sentence of finding. You reconcile the totals several ways before you call it done. The file is something you can show as evidence of your skill, as long as you say clearly that the data is a practice database.
Certificate. Finish every lesson, resolve every quiz question with at least 50% right on the first try, and tick the capstone checklist — Apex Flow Academy issues a verifiable Certificate of Completion with a unique ID and a public verification page. It is a certificate of completion, not a degree, licence, accreditation or exam result.
01 · Look at Your Data4 lessons
Build the Fernwood practice database, then learn the four moves that answer many simple questions: choose columns, remove repeats, sort, trim and calculate new columns.
- 1.1Build Your Practice DatabaseFREE
- 1.2SELECT and FROM: Choose Your Columns
- 1.3ORDER BY and LIMIT: Sort and Trim
- 1.4New Columns From Old: Calculations and AS
02 · Pick the Rows You Want4 lessons
Learn to keep only the rows that matter: comparisons, AND and OR with parentheses, lists and ranges, and text patterns.
- 2.1WHERE: Keep Only the Rows You Want
- 2.2AND, OR, NOT and Parentheses
- 2.3IN and BETWEEN: Lists and Ranges
- 2.4LIKE: Match Patterns in Text
03 · Totals, Groups and Missing Values4 lessons
Turn many rows into answers: count, add and average with summary functions, split them into groups, filter the groups, and handle missing values safely.
- 3.1Summary Functions: COUNT, SUM, AVG, MIN, MAX
- 3.2GROUP BY: One Row for Each Group
- 3.3HAVING: Filter the Groups
- 3.4NULL: When a Value Is Missing
04 · Combine Tables With Joins4 lessons
Connect the four Fernwood tables: match rows with INNER JOIN, chain several tables, keep unmatched rows with LEFT JOIN, and check that a join has not quietly changed your numbers.
- 4.1INNER JOIN: Connect Two Tables
- 4.2Join Three or Four Tables
- 4.3LEFT JOIN: Keep Rows With No Match
- 4.4Check Your Joins: Counts and Totals
05 · Shape and Deepen Your Answers4 lessons
Label rows with CASE, work with dates, and break bigger questions into steps with subqueries and WITH.
- 5.1CASE: Label and Bucket Rows
- 5.2Dates: Group and Measure by Month
- 5.3Subqueries: A Query Inside a Query
- 5.4WITH: Name Each Step of a Query
06 · Pro Moves and the Capstone4 lessons
Rank and total without losing rows, change data safely, debug errors and silent wrong answers, then assemble your finished business-questions report.
- 6.1Window Functions: Rank Without Collapsing Rows
- 6.2Change Data Safely: INSERT, UPDATE, DELETE
- 6.3When a Query Fails or Looks Wrong
- 6.4Capstone: Your Business-Questions Report
Build Your Practice Database
You will be able to
- Say what a table, a row and a column are.
- Build the Fernwood practice database and check that it loaded.
Why this matters
You learn SQL by asking a database questions, so you need one to ask. This one is small on purpose, so you can hold all of it in your head. Every lesson uses it, and each lesson ends with a short task. Do the tasks; typing queries is how the skill sticks. Each module adds a section to a report you will finish as your capstone.
Learn it
A database is an organized place to keep facts. A table is one list inside it, drawn as a grid. A column is one kind of fact, such as a price. A row is one thing, such as one product.
Our practice shop is Fernwood, a small plant shop. It has four tables: customers, products, orders (one row per purchase) and order_items (which products were in each order).
A primary key is a column whose value differs in every row, so it names that row. A foreign key holds another table's key. In orders, customer_id points at a row in customers. The order_items table has a key made of two columns, because one order can hold many products.
SQL is a shared language, but each database adds small differences. This course runs every query on SQLite, which is free and needs no server. Notes flag where PostgreSQL, MySQL or SQL Server differ. They come from those tools' documentation; only SQLite was run.
To build the database with DB Browser for SQLite (free; check its website for the current download):
- Install it and open it.
- Choose New Database, name the file fernwood.db and save it. If a window asks you to define a table, cancel it.
- Open the Execute SQL tab and paste the whole script from the next section.
- Run all of it (look for an Execute all button).
- Choose Write Changes so the tables are saved into the file.
If this is not working: check that you pasted everything, from the first CREATE to the last semicolon. To skip the install, the workbook has a short Python runner, because Python includes SQLite.
See it in action
Copy this script exactly and run it once.
CREATE TABLE customers (
customer_id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT,
city TEXT,
signup_date TEXT
);
CREATE TABLE products (
product_id INTEGER PRIMARY KEY,
name TEXT,
category TEXT,
price REAL
);
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER REFERENCES customers(customer_id),
order_date TEXT,
status TEXT,
shipped_date TEXT
);
CREATE TABLE order_items (
order_id INTEGER REFERENCES orders(order_id),
product_id INTEGER REFERENCES products(product_id),
quantity INTEGER,
PRIMARY KEY (order_id, product_id)
);
INSERT INTO customers VALUES
(1,'Ana','Ruiz','Austin','2023-11-05'),
(2,'Ben','Carter','Denver','2023-12-14'),
(3,'Chloe','Nguyen','Austin','2024-01-20'),
(4,'Dev','Patel','Seattle','2024-02-02'),
(5,'Elena','Rossi','Denver','2024-02-18'),
(6,'Farid','Khan','Chicago','2024-03-09'),
(7,'Grace','Liu','Seattle','2024-03-27'),
(8,'Hugo','Silva','Austin','2024-04-11'),
(9,'Isla','Brown','Portland','2024-05-06'),
(10,'Jack','Wilson','Chicago','2024-06-01');
INSERT INTO products VALUES
(1,'Snake Plant','Plants',18.0),
(2,'Monstera','Plants',32.5),
(3,'Pothos','Plants',12.0),
(4,'Cactus Trio','Plants',24.0),
(5,'Terracotta Pot','Pots',9.5),
(6,'Ceramic Pot','Pots',21.0),
(7,'Hanging Planter','Pots',15.0),
(8,'Watering Can','Tools',14.5),
(9,'Pruning Shears','Tools',19.0),
(10,'Plant Food','Care',7.5);
INSERT INTO orders VALUES
(1,1,'2024-01-08','shipped','2024-01-10'),
(2,2,'2024-01-15','shipped','2024-01-18'),
(3,1,'2024-02-03','shipped','2024-02-05'),
(4,3,'2024-02-11','shipped','2024-02-12'),
(5,4,'2024-02-25','shipped','2024-02-28'),
(6,5,'2024-03-04','shipped','2024-03-06'),
(7,2,'2024-03-19','cancelled',NULL),
(8,6,'2024-03-30','shipped','2024-04-02'),
(9,3,'2024-04-08','shipped','2024-04-09'),
(10,7,'2024-04-22','shipped','2024-04-25'),
(11,1,'2024-05-06','shipped','2024-05-08'),
(12,4,'2024-05-14','pending',NULL),
(13,6,'2024-05-29','shipped','2024-06-01'),
(14,5,'2024-06-10','shipped','2024-06-12'),
(15,8,'2024-06-18','pending',NULL);
INSERT INTO order_items VALUES
(1,1,1),(1,5,2),
(2,2,1),(2,8,1),
(3,3,2),(3,10,1),
(4,4,1),(4,6,1),
(5,1,2),(5,9,1),
(6,2,1),(6,6,2),
(7,9,1),
(8,3,3),(8,5,3),(8,10,1),
(9,1,1),(9,8,1),
(10,4,2),(10,6,1),(10,10,2),
(11,2,2),
(12,3,1),(12,5,1),
(13,1,1),(13,10,3),
(14,8,2),(14,9,1),
(15,4,1);Now check that every row arrived. This query counts the rows in each table; ignore how it works for now.
SELECT (SELECT COUNT(*) FROM customers) AS customers,
(SELECT COUNT(*) FROM products) AS products,
(SELECT COUNT(*) FROM orders) AS orders,
(SELECT COUNT(*) FROM order_items) AS items;customers products orders items
--------- -------- ------ -----
10 10 15 29Your program may draw the grid differently; the values matter.
Common mistakes
- Running the script twice. Every CREATE TABLE then fails because the table already exists. Fix: delete fernwood.db and start again with a fresh file.
- Forgetting Write Changes. The tables vanish when you close the program. Fix: save, then reopen the file to confirm.
- Pasting part of the script. You get an error or empty tables. Fix: select all and paste again.
You are done when
The count query shows 10, 10, 15 and 29, and you can point to a primary key and a foreign key in the orders table.
You finished the free lesson
That is one lesson from the course. The full course gives you every remaining lesson, a quick check and a hands-on task in each one, and the workbook of templates and checklists.
Full course$39
- A computer running Windows, macOS or Linux.
- DB Browser for SQLite, which is free and open source. Check its website for the current download. Or use Python, which is also free and includes SQLite; the workbook has a short runner script for it.
- A plain text editor for your report file. Any free editor works.
- Nothing in this course needs a paid tool or a subscription.
- No coding or database experience is needed.
- You can install a free program and copy and paste text.
- You can read a simple table, the way you would in a spreadsheet.
The Fernwood Business-Questions Report
You finish one SQL file, fernwood_report.sql, that answers ten business questions about the practice shop. Every entry has the question, the query, the pasted result and one honest sentence of finding. You reconcile the totals several ways before you call it done. The file is something you can show as evidence of your skill, as long as you say clearly that the data is a practice database.
- A file named fernwood_report.sql with a header that holds your name, the date, the business rule that revenue counts shipped orders only, and a note that the data is practice data.
- Ten entries, each with the question as a comment, the query, the result pasted from a fresh run, and a one-sentence finding.
- A reconciliation comment at the end that lists four routes to the same shipped revenue total: by category, by month, by customer and by order.
- A short list, as comments, of at least three mistakes you made during the course and how you fixed them.
- Database
- An organized place to keep facts, made up of tables that can be linked together.
- Table
- One list inside a database, drawn as a grid of rows and columns.
- Row
- One record in a table, such as one product or one order.
- Column
- One kind of fact in a table, such as a price or a city. Every row has a value for it.
- Primary key
- A column whose value is different in every row, so it names that row for good.
- Foreign key
- A column that holds another table's key, which is how one table points at a row in another.
- Query
- A written request to the database, such as a SELECT that asks for certain rows.
- Clause
- One part of a query that starts with a keyword, such as FROM, WHERE or ORDER BY.
- Alias
- A short nickname you give a column or a table, using AS.
- NULL
- A marker that means no value is stored. It is not zero and not an empty piece of text.
- Aggregate function
- A function such as COUNT, SUM, AVG, MIN or MAX that turns many rows into one value.
- GROUP BY
- A clause that puts rows into piles that share a value, so you get one summary row per pile.
Browse the full Academy encyclopedia
16 checks were run and recorded while writing this course (code, formulas, commands and facts), and it lists 23 official sources it was checked against. Prices, features and policies of outside tools can change, so check each tool's own website.
Created by Apex Flow Academy with AI assistance. For education only; not legal, tax, financial or medical advice. Results depend on your effort and circumstances.
Python From Zero: Write Programs That Work
You write and run real Python programs from the first lesson, and you finish with three small working tools that you built yourself, tested with checks you wrote, and can change without starting over.
Python Automation: Make the Computer Do Your Boring Work
You automate files, spreadsheets, email drafts and web lookups that eat your week. You finish with your own script that plans before it acts, keeps a log, is tested against sample data, and runs on a schedule.
Data Analytics From Scratch: Answer Real Business Questions
You collect, clean, analyse and present data so a boss can act on it. By the end you will have worked through the whole analytics loop on one practice dataset and produced a case study with charts and a written recommendation that states how sure you are and what the data cannot show.