SQL for beginners: the 10 queries to learn first
A practical guide to the ten SQL queries that cover most of what beginners need: SELECT, WHERE, ORDER BY, GROUP BY, JOIN, and safe UPDATE and DELETE.

Most SQL tutorials start with theory: relational algebra, normal forms, a tour of every keyword. You don't need any of that on day one.
A small set of queries does the heavy lifting in real projects. Learn these ten, in this order, and you can answer most of the questions people actually ask a database.
All the examples use two tables from a made-up online shop:
customers(id, name, country)
orders(id, customer_id, total, status, ordered_at)Each customer can have many orders, and orders.customer_id points back to customers.id. The syntax works in PostgreSQL, SQLite and MySQL unless noted.
1. SELECT: look at your data
Every read starts here. Pick the columns you want and the table they live in.
SELECT name, country
FROM customers;SELECT * returns every column, which is fine for poking around. In code you want to ask for only what you need.
Want nicer column names in the output? Rename them with AS:
SELECT name AS customer_name, country
FROM customers;2. WHERE: filter rows
WHERE keeps only the rows that match a condition.
SELECT id, total
FROM orders
WHERE status = 'shipped';Text goes in single quotes. Numbers don't. Comparisons you'll use constantly: =, <> (not equal), <, >, <=, >=.
3. AND, OR, IN, LIKE and NULL: filter smarter
Real questions have more than one condition.
SELECT id, total, status
FROM orders
WHERE total > 100
AND (status = 'shipped' OR status = 'delivered');The parentheses matter. AND binds tighter than OR, so without them you get a different answer.
Two shortcuts make this tidier:
-- Match any value in a list
SELECT * FROM orders WHERE status IN ('shipped', 'delivered');
-- Partial text match: names starting with "A"
SELECT * FROM customers WHERE name LIKE 'A%';Then there's the classic trap: missing values. NULL means "unknown", and nothing equals it, not even another NULL. Use IS NULL:
SELECT * FROM customers WHERE country IS NULL; -- works
SELECT * FROM customers WHERE country = NULL; -- returns nothing, ever4. ORDER BY and LIMIT: sort and trim
Tables have no guaranteed order. If order matters, ask for it.
SELECT id, total
FROM orders
ORDER BY total DESC
LIMIT 5;That's your five biggest orders. ASC is the default direction, DESC reverses it. You can sort by several columns: ORDER BY country, name.
5. COUNT, SUM, AVG, MIN, MAX: summarize
Aggregate functions collapse many rows into one answer.
SELECT
COUNT(*) AS order_count,
SUM(total) AS revenue,
AVG(total) AS average_order,
MAX(total) AS biggest_order
FROM orders;COUNT(*) counts rows. COUNT(column) counts only the rows where that column isn't NULL, a difference that surprises people.
6. GROUP BY: summarize per category
Totals are useful. Totals per customer, per country or per month are where it gets interesting.
SELECT customer_id, COUNT(*) AS orders, SUM(total) AS spent
FROM orders
GROUP BY customer_id;The rule of thumb: every column in SELECT must either be in the GROUP BY or wrapped in an aggregate function.
7. HAVING: filter the groups
WHERE filters rows before grouping. HAVING filters the groups after.
SELECT customer_id, SUM(total) AS spent
FROM orders
GROUP BY customer_id
HAVING SUM(total) > 500
ORDER BY spent DESC;This returns only customers who've spent more than 500, biggest spenders first. If you try this condition in WHERE, the database will complain, because the sum doesn't exist yet at that stage.
8. JOIN: combine tables
Orders are only useful if you know whose they are. JOIN stitches two tables together on a shared column.
SELECT customers.name, orders.id, orders.total
FROM orders
JOIN customers ON customers.id = orders.customer_id;Short aliases keep this readable once queries grow:
SELECT c.name, o.id, o.total
FROM orders AS o
JOIN customers AS c ON c.id = o.customer_id;A plain JOIN (an inner join) returns only rows that have a match on both sides. For the other join types, with a worked example of each, see SQL Joins Explained with Simple Examples.
9. LEFT JOIN: keep the unmatched rows
What if you want every customer, including the ones who never ordered? An inner join drops them. A LEFT JOIN keeps everything from the left table and fills the gaps with NULL.
SELECT c.name, COUNT(o.id) AS orders
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.id
GROUP BY c.id, c.name
ORDER BY orders ASC;Customers with zero orders now show up with a count of 0. This pattern, "find the things with none of the other thing", is one of the most useful in all of SQL. We take it apart step by step in our guide to SQL joins.
10. INSERT, UPDATE and DELETE: change data safely
The first nine queries only read. The last one writes, and writing is where mistakes get expensive.
INSERT INTO customers (name, country)
VALUES ('Ada', 'UK');
UPDATE orders
SET status = 'cancelled'
WHERE id = 42;
DELETE FROM orders
WHERE id = 42;The most important habit in this whole article: always write the WHERE. An UPDATE or DELETE without one touches every row in the table.
A safe routine:
- Write the
WHEREas aSELECTfirst and check the rows it returns. - Swap
SELECT *forUPDATE ... SETorDELETE. - Run it inside a transaction (
BEGIN; ... COMMIT;) if your database supports it, so you canROLLBACKif the result looks wrong.
Postgres and SQLite also support RETURNING, which shows you the rows you just changed: UPDATE orders SET status = 'cancelled' WHERE id = 42 RETURNING *;
The order SQL actually runs in
You write SELECT first, but the database doesn't run it first. Roughly, the order is:
FROMandJOIN: find and combine the tablesWHERE: filter rowsGROUP BY: form groupsHAVING: filter groupsSELECT: compute the output columnsORDER BYandLIMIT: sort and trim
This explains most beginner errors. You can't use a SELECT alias inside WHERE, for example, because WHERE runs before the alias exists.
How to practice
Reading about queries only gets you so far. Type them out, break them, and see what the database says. Start with one table, ask ten small questions, then add the second table and repeat.
If you want a guided path through exactly these topics, the Learn SQL (opens in a new tab) course walks through them with runnable exercises. These lessons map directly to the queries above:
- Queries 2 and 3: The Where Clause (opens in a new tab)
- Query 4: Sorting With Order By (opens in a new tab)
- Query 6: Grouping Rows With Group By (opens in a new tab)
- Query 7: Filtering Groups With Having (opens in a new tab)
- Query 8: Joining Two Tables (opens in a new tab)
- Query 9: Keeping Unmatched Rows With Left Join (opens in a new tab)
- Query 10: Changing Rows With Update (opens in a new tab) and Checking Before You Change (opens in a new tab)
Ten queries won't make you a database expert, but they will let you answer real questions with real data. That's the point where SQL stops feeling like a syllabus and starts feeling like a tool.





