How to read this sheet
Each card gives a pattern (the template) and usually an example (a real query you could run). Words like table_name, column and employees are placeholders, swap in your own table and column names.
SELECTkeywordsCOUNTfunctions'text'text values123numbers-- notecommentsSELECT department, COUNT(*) AS headcount -- columns to show FROM employees -- the source table WHERE salary > 50000 -- filter rows first GROUP BY department -- collapse into groups HAVING COUNT(*) > 3 -- filter the groups ORDER BY headcount DESC -- sort the result LIMIT 10; -- cap the rows
You write the clauses in this order, but the database runs them in a different one. See Query Execution Order at the end.
Retrieving Data
SELECTChoose which columns to return.
SELECT column1, column2 FROM table_name;
SELECT name, department FROM employees;
SELECT *Return every column. Handy while exploring, but name the columns you need in real queries.
SELECT * FROM table_name;
AS (Alias)Rename a column in the result.
SELECT column AS alias_name FROM table_name;
SELECT first_name AS "First Name" FROM employees;
DISTINCTRemove duplicate rows from results.
SELECT DISTINCT column FROM table_name;
SELECT DISTINCT department FROM employees;
Filtering Rows
WHEREKeep only the rows that match a condition. Operators: = != < > <= >=
SELECT * FROM table_name WHERE condition;
SELECT * FROM employees WHERE department = 'Sales';
ANDBoth conditions must be true.
SELECT * FROM employees WHERE department = 'Sales' AND salary > 50000;
OREither condition can be true. Use parentheses to control precedence.
SELECT * FROM employees WHERE city = 'NYC' OR city = 'LA';
INMatch any value in a list. Shorter than chaining lots of ORs.
SELECT * FROM employees WHERE department IN ('Sales', 'Marketing', 'HR');
BETWEENMatch a range of values (inclusive of both ends).
SELECT * FROM employees WHERE salary BETWEEN 40000 AND 80000;
LIKEPattern matching for text. % = any number of characters, _ = exactly one.
SELECT * FROM employees WHERE name LIKE 'J%'; SELECT * FROM employees WHERE name LIKE '_ohn';
IS NULL / IS NOT NULLCheck for missing values.
SELECT * FROM employees WHERE manager_id IS NULL;
Sorting & Limiting
ORDER BYSort results. ASC (default) = ascending, DESC = descending.
SELECT * FROM employees ORDER BY salary DESC; -- Multiple columns SELECT * FROM employees ORDER BY department ASC, salary DESC;
LIMITReturn only the first N rows. Pair with ORDER BY to get a real top-N.
SELECT * FROM employees ORDER BY salary DESC LIMIT 5;
OFFSETSkip rows before returning. Useful for pagination.
SELECT * FROM employees LIMIT 10 OFFSET 20;
Aggregate Functions
COUNT / SUM / AVG / MIN / MAXCollapse many rows into a single value.
SELECT COUNT(*) AS total_employees, AVG(salary) AS avg_salary, MAX(salary) AS top_salary, MIN(salary) AS lowest_salary, SUM(salary) AS payroll FROM employees;
GROUP BYGroup rows that share a value, then aggregate each group separately.
SELECT department, COUNT(*) AS headcount FROM employees GROUP BY department;
HAVINGFilter groups after aggregation, like WHERE but for grouped results.
SELECT department, AVG(salary) AS avg_sal FROM employees GROUP BY department HAVING AVG(salary) > 60000;
JOINs - Combining Tables
Visual reference
Orange shows which rows each JOIN keeps. A = left table, B = right table.
Need the rows with no match? LEFT JOIN ... WHERE b.id IS NULL
INNER JOINOnly rows that have a match in both tables.
SELECT e.name, d.department_name FROM employees e INNER JOIN departments d ON e.dept_id = d.id;
LEFT JOINAll rows from the left table, plus matches from the right (NULL where there is none).
SELECT e.name, d.department_name FROM employees e LEFT JOIN departments d ON e.dept_id = d.id;
RIGHT JOINAll rows from the right table, plus matches from the left.
SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id;
FULL OUTER JOINAll rows from both tables, with NULLs wherever there is no match.
SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id;
String Functions
Common String FunctionsTransform and inspect text values.
UPPER('hello') → 'HELLO' LOWER('HELLO') → 'hello' LENGTH('hello') → 5 TRIM(' hello ') → 'hello' CONCAT('hello', ' world') → 'hello world' SUBSTRING('hello', 1, 3) → 'hel' REPLACE('hello', 'l', 'r') → 'herro'
Date Functions
Common Date FunctionsWork with dates and times. Exact names vary by database.
CURRENT_DATE -- today's date CURRENT_TIMESTAMP -- current date + time EXTRACT(YEAR FROM date) -- pull part of a date DATE_DIFF(date1, date2) -- days between dates
Subqueries
Subquery in WHEREUse a query inside another query to filter results.
SELECT * FROM employees WHERE dept_id IN ( SELECT id FROM departments WHERE location = 'NYC' );
Subquery in FROMUse a query as a temporary table (a derived table).
SELECT * FROM ( SELECT department, COUNT(*) AS cnt FROM employees GROUP BY department ) sub WHERE sub.cnt > 5;
Query Execution Order
Execution order
SQL clauses run in this order, not the order you write them
This is why WHERE cannot use a column alias from SELECT (SELECT runs later), and why HAVING can filter on a COUNT(*) that WHERE cannot.