Wernzi Tools

Wernzi Tools Guide

SQL Basics for Beginners

SQL is the language of databases: SELECT, WHERE, JOIN and GROUP BY cover most of what you will ever need. A beginner-friendly introduction with examples.

By Wernzi Tools team · Published November 7, 2026 · 7 min read · Updated November 2026

Almost every app you use stores its data in a database, and almost every database answers to SQL — Structured Query Language. With a handful of commands you can ask for exactly the data you need: every customer who ordered this month, the ten best-selling products, the average order value by country. SQL has been the standard since the 1970s, and it is still the most valuable data skill you can learn.

This guide teaches the core of SQL with small, runnable examples: reading data, filtering it, combining tables and summarizing results. You will be able to read real queries by the end — and write your own.

Tables, rows and columns

A relational database stores data in tables. A table is like a spreadsheet: each column is one kind of field, and each row is one record. A customers table might have columns for id, name, email and country; each row is one customer. Every table should have a primary key — a column (or combination of columns) that uniquely identifies each row, usually an id — so that other tables can refer to a row unambiguously.

Tables relate to each other through these keys. An orders table has a customer_id column that points at the id of a customer: that link is called a foreign key, and it is what lets you ask questions that span tables, like "which customers ordered in the last month?" Understanding tables and keys is the foundation — SQL itself is mostly just a way of describing which rows you want from which tables.

SELECT: asking for data

The SELECT statement is how you read data, and it reads almost like English: SELECT name, email FROM customers asks for the name and email of every customer. The asterisk is a shortcut for "all columns" — SELECT * FROM customers — useful for exploring, but in real code you should name the columns you need, because it makes the query faster and protects you when the table gains new columns.

Two small clauses complete the picture. LIMIT restricts how many rows come back — SELECT * FROM customers LIMIT 10 returns just the first ten — and aliases rename columns in the output with AS: SELECT name AS customer_name FROM customers. Note that SELECT never changes the data; it only reads it. That makes it the safest statement in SQL, and the best place to start learning.

SELECT name, email
FROM customers;

SELECT *
FROM orders
LIMIT 10;

SELECT name AS customer_name, country
FROM customers;

WHERE: filtering rows

WHERE filters rows before they are returned: SELECT * FROM orders WHERE total > 100 returns only the orders over 100. Conditions use the usual comparisons — =, <, >, <=, >=, <> for "not equal" — and can be combined with AND, OR and NOT. For sets of values, IN is cleaner than a chain of ORs: WHERE country IN ('US', 'UK', 'CA'). For ranges, BETWEEN works: WHERE order_date BETWEEN '2026-10-01' AND '2026-10-31'.

Three details catch beginners. First, text matching with LIKE uses % as a wildcard: WHERE name LIKE 'A%' finds names starting with A. Second, NULL is not a value — it means "unknown", so you must test it with IS NULL or IS NOT NULL, because WHERE email = NULL never matches anything. Third, WHERE runs before SELECT picks its columns, so you cannot filter on an alias defined in the same SELECT — filter on the original column instead.

  • =, <, >, <=, >=, <> — basic comparisons
  • AND, OR, NOT — combine conditions
  • IN (...) — match any value in a list
  • BETWEEN ... AND ... — match a range
  • LIKE 'A%' — pattern matching (% = any characters)
  • IS NULL / IS NOT NULL — the only way to test for NULL

JOIN: combining tables

Real questions span tables, and JOIN is how you combine them. An INNER JOIN returns only rows that match in both tables: SELECT orders.id, customers.name FROM orders INNER JOIN customers ON orders.customer_id = customers.id pairs each order with the customer who placed it, and drops orders whose customer is missing. A LEFT JOIN keeps every row from the left table and fills in NULLs where the right table has no match — useful for finding customers who have never ordered.

Joins are where SQL earns its keep, and where its classic mistake lives: joining on the wrong column, or forgetting a join condition entirely, multiplies rows in ways that look plausible but are wrong. Always join on keys — the foreign key to the primary key — and check the row count: if a query that should return 50 rows returns 5,000, a join went wrong. When a query you inherited is hard to read, a SQL formatter that re-indents it can turn a wall of text into something you can follow.

-- Orders with the customer who placed them
SELECT orders.id, customers.name, orders.total
FROM orders
INNER JOIN customers
  ON orders.customer_id = customers.id;

-- Customers who never ordered (NULL = no match)
SELECT customers.name
FROM customers
LEFT JOIN orders
  ON orders.customer_id = customers.id
WHERE orders.id IS NULL;

GROUP BY and aggregates: summarizing

Aggregate functions summarize many rows into one number: COUNT(*) counts rows, SUM(total) adds a column, AVG(total) averages it, MIN and MAX find the extremes. On their own they collapse the whole result into a single row — but combined with GROUP BY, they summarize per group: SELECT country, COUNT(*) FROM customers GROUP BY country counts customers per country.

The rule that trips everyone up is WHERE versus HAVING: WHERE filters individual rows before grouping, HAVING filters groups after grouping. To find countries with more than 100 customers, you write GROUP BY country HAVING COUNT(*) > 100 — a WHERE on COUNT(*) would be an error. Add ORDER BY to sort the result and LIMIT to take the top few, and you have the classic reporting query: SELECT country, SUM(total) AS revenue FROM orders GROUP BY country ORDER BY revenue DESC LIMIT 5 gives you the five biggest markets.

-- Revenue by country, top 5
SELECT country, SUM(total) AS revenue
FROM orders
GROUP BY country
ORDER BY revenue DESC
LIMIT 5;

Try it yourself

Put what you just read into practice with these free tools — no sign-up needed.

Keep learning

Browse all guides →