Complete Reference · Free Download

SQL Syntax
Quick Guide

Every essential SQL command in one place — SELECT, JOINs, aggregates, subqueries, window functions, indexes, stored procedures and more. Curated for beginners to advanced developers.

Browse Cheat Sheet ↓
16+Topics Covered
200+SQL Examples
8 pagesPDF Download
FreeAlways
Fundamentals

SELECT Basics

The SELECT statement is the foundation of every SQL query — retrieve, sort and limit records from any table.

📋
SELECT Statement
Retrieve data from one or more columns, with aliases and expressions.
sql
-- Select all columns
SELECT * FROM employees;

-- Select specific columns
SELECT first_name, last_name, salary
FROM employees;

-- Column aliases
SELECT
  first_name AS "First Name",
  salary * 12 AS annual_salary,
  UPPER(department) AS dept
FROM employees;

-- Distinct values
SELECT DISTINCT department
FROM employees;

-- Limit results
SELECT * FROM employees LIMIT 10;
SELECT * FROM employees LIMIT 10 OFFSET 20; -- skip 20
📐
ORDER BY & Query Order
Sort results and understand the correct clause execution order.
sql
-- Sort ascending (default)
SELECT * FROM employees
ORDER BY last_name ASC;

-- Sort descending
SELECT * FROM employees
ORDER BY salary DESC;

-- Multi-column sort
SELECT * FROM employees
ORDER BY department ASC, salary DESC;

-- SQL Execution Order:
-- 1. FROM / JOIN   2. WHERE
-- 3. GROUP BY      4. HAVING
-- 5. SELECT        6. DISTINCT
-- 7. ORDER BY      8. LIMIT/OFFSET

🗂️ Common SQL Data Types

Category Data Type Description Example
Numeric INT / INTEGER Whole numbers (4 bytes) age INT
Numeric BIGINT Large whole numbers (8 bytes) user_id BIGINT
Numeric DECIMAL(p,s) Exact fixed-point number price DECIMAL(10,2)
Numeric FLOAT / DOUBLE Approximate floating point rate FLOAT
Text VARCHAR(n) Variable-length string name VARCHAR(100)
Text CHAR(n) Fixed-length string code CHAR(3)
Text TEXT Unlimited text content bio TEXT
Date/Time DATE Date only: YYYY-MM-DD dob DATE
Date/Time DATETIME / TIMESTAMP Date and time combined created_at TIMESTAMP
Other BOOLEAN TRUE / FALSE is_active BOOLEAN
Other JSON JSON document (MySQL 5.7+) metadata JSON
Querying

Filtering & Conditions

Narrow down results with WHERE clauses — comparison operators, logical operators, LIKE, BETWEEN, IN and NULL checks.

🔍
WHERE Clause
Filter rows using comparison and logical operators.
sql
-- Comparison operators
SELECT * FROM employees
WHERE salary > 50000;

WHERE age >= 30 AND age <= 50;
WHERE department = 'Sales';
WHERE department != 'HR';  -- or <>

-- Logical operators
WHERE salary > 60000 AND dept = 'IT';
WHERE dept = 'Sales' OR  dept = 'IT';
WHERE NOT is_active = 0;

-- NULL checks
WHERE manager_id IS NULL;
WHERE phone      IS NOT NULL;
🎯
IN, BETWEEN & LIKE
Match lists, ranges and patterns in your WHERE clauses.
sql
-- IN: match list of values
WHERE department IN ('Sales', 'IT', 'HR');
WHERE id NOT IN (1, 2, 3);

-- BETWEEN: inclusive range
WHERE salary BETWEEN 40000 AND 80000;
WHERE hire_date BETWEEN
      '2020-01-01' AND '2023-12-31';

-- LIKE: pattern matching
WHERE name LIKE    'A%';   -- starts with A
WHERE name LIKE    '%son'; -- ends with son
WHERE email LIKE   '%@gmail%';
WHERE code LIKE    'A_C';  -- _ = one char

-- Case-insensitive (MySQL)
WHERE LOWER(name) LIKE '%john%';
🧪
CASE Expression
Conditional logic inline — like IF/ELSE inside a query.
sql
-- Simple CASE
SELECT name,
  CASE department
    WHEN 'IT'    THEN 'Tech'
    WHEN 'HR'    THEN 'People'
    ELSE               'Other'
  END AS dept_group
FROM employees;

-- Searched CASE
SELECT name, salary,
  CASE
    WHEN salary < 40000  THEN 'Junior'
    WHEN salary < 80000  THEN 'Mid'
    ELSE                         'Senior'
  END AS level
FROM employees;

-- CASE in ORDER BY
ORDER BY
  CASE status
    WHEN 'urgent' THEN 1
    WHEN 'normal' THEN 2
    ELSE 3
  END;
Relationships

JOINs

Combine rows from two or more tables based on a related column — the heart of relational databases.

🔗
INNER & LEFT JOIN
The two most commonly used join types.
sql
-- INNER JOIN: only matched rows
SELECT e.name, d.dept_name
FROM  employees e
INNER JOIN departments d
  ON e.dept_id = d.id;

-- LEFT JOIN: all from left table
SELECT e.name, d.dept_name
FROM  employees e
LEFT JOIN departments d
  ON e.dept_id = d.id;
-- NULLs where no dept match

-- Find unmatched rows
SELECT e.*
FROM employees e
LEFT JOIN departments d
  ON e.dept_id = d.id
WHERE d.id IS NULL;
⬅️➡️
RIGHT, FULL & CROSS JOIN
Less-common but powerful join types for complete data sets.
sql
-- RIGHT JOIN: all from right table
SELECT e.name, d.dept_name
FROM employees e
RIGHT JOIN departments d
  ON e.dept_id = d.id;

-- FULL OUTER JOIN: all rows, both
SELECT *
FROM employees e
FULL OUTER JOIN departments d
  ON e.dept_id = d.id;

-- CROSS JOIN: cartesian product
SELECT a.color, b.size
FROM colors a
CROSS JOIN sizes b;

-- SELF JOIN: table joins itself
SELECT e.name, m.name AS manager
FROM employees e
LEFT JOIN employees m
  ON e.manager_id = m.id;
🏗️
Multi-Table & Complex JOINs
Joining more than two tables and using compound conditions.
sql
-- Three-table join
SELECT
  o.order_id,
  c.name       AS customer,
  p.product_name
FROM  orders   o
JOIN  customers c ON o.cust_id    = c.id
JOIN  products  p ON o.product_id = p.id;

-- JOIN with multiple conditions
JOIN prices pr
  ON p.id   = pr.product_id
 AND pr.region = 'US';

-- JOIN with subquery
JOIN (
  SELECT dept_id, AVG(salary) avg_sal
  FROM  employees
  GROUP BY dept_id
) ds ON e.dept_id = ds.dept_id;

🔗 JOIN Types Quick Reference

JOIN Type Returns Use When
INNER JOIN Only rows with matches in BOTH tables You only want complete data
LEFT JOIN All left + matched right (NULLs for no match) Keep all left rows, optional right
RIGHT JOIN All right + matched left (NULLs for no match) Keep all right rows, optional left
FULL OUTER JOIN All rows from both, NULLs where no match Find all records regardless of match
CROSS JOIN Cartesian product of both tables Generate all combinations
SELF JOIN Table joined to itself Hierarchical / parent-child data
Analytics

Aggregate Functions & GROUP BY

Summarise data with COUNT, SUM, AVG, MIN, MAX — and filter groups with HAVING.

📊
Aggregate Functions
Compute summary values across rows of data.
sql
-- COUNT
SELECT COUNT(*)               FROM employees;
SELECT COUNT(manager_id)      FROM employees; -- non-NULL
SELECT COUNT(DISTINCT dept)  FROM employees;

-- SUM / AVG / MIN / MAX
SELECT
  SUM(salary)          AS total_payroll,
  AVG(salary)          AS avg_salary,
  MIN(salary)          AS min_salary,
  MAX(salary)          AS max_salary,
  ROUND(AVG(salary),2) AS avg_rounded
FROM employees;

-- GROUP_CONCAT (MySQL)
SELECT dept,
  GROUP_CONCAT(name ORDER BY name
               SEPARATOR ', ') AS members
FROM employees GROUP BY dept;
🗂️
GROUP BY & HAVING
Group rows by a column and filter aggregated results.
sql
-- GROUP BY: summarise per group
SELECT
  department,
  COUNT(*)        AS headcount,
  AVG(salary)     AS avg_salary,
  MAX(salary)     AS top_salary
FROM  employees
GROUP BY department
ORDER BY headcount DESC;

-- HAVING: filter on aggregated values
-- (use HAVING not WHERE for aggregates)
SELECT department, COUNT(*) AS cnt
FROM  employees
GROUP BY department
HAVING COUNT(*) > 5;

-- WHERE + GROUP BY + HAVING
SELECT dept, SUM(sales) AS total
FROM  orders
WHERE  year = 2024
GROUP BY dept
HAVING SUM(sales) > 100000
ORDER BY total DESC;
Nesting

Subqueries & CTEs

Nest queries inside queries or use Common Table Expressions (WITH) for readable, reusable logic.

🔄
Subqueries
Use a query result as a value, list or table.
sql
-- Scalar subquery (single value)
SELECT * FROM employees
WHERE salary > (
  SELECT AVG(salary) FROM employees
);

-- IN subquery (list)
SELECT * FROM employees
WHERE dept_id IN (
  SELECT id FROM departments
  WHERE location = 'NYC'
);

-- Derived table (FROM subquery)
SELECT dept, avg_sal
FROM (
  SELECT department dept,
         AVG(salary) avg_sal
  FROM  employees
  GROUP BY department
) dept_summary
WHERE avg_sal > 60000;
🧩
EXISTS & Correlated
Check existence and use outer-query values inside a subquery.
sql
-- EXISTS: check if any rows exist
SELECT * FROM customers c
WHERE EXISTS (
  SELECT 1 FROM orders o
  WHERE o.cust_id = c.id
);

-- NOT EXISTS
WHERE NOT EXISTS (
  SELECT 1 FROM orders o
  WHERE o.cust_id = c.id
);

-- ANY / ALL comparisons
WHERE salary > ANY (
  SELECT salary FROM managers
);
WHERE salary > ALL (
  SELECT salary FROM managers
);
📝
Common Table Expressions (CTE)
Named temporary results with WITH — cleaner than nested subqueries.
sql
-- Basic CTE
WITH dept_avg AS (
  SELECT dept_id, AVG(salary) avg_sal
  FROM  employees
  GROUP BY dept_id
)
SELECT e.*, da.avg_sal
FROM  employees e
JOIN  dept_avg  da ON e.dept_id = da.dept_id;

-- Multiple CTEs
WITH
  top_earners AS (
    SELECT * FROM employees
    WHERE salary > 100000
  ),
  their_depts AS (
    SELECT DISTINCT dept_id
    FROM top_earners
  )
SELECT * FROM their_depts;
Schema Design

DDL — Data Definition Language

CREATE, ALTER and DROP tables, columns, constraints and relationships that define your database schema.

🏗️
CREATE TABLE
Define new tables with columns, types and constraints.
sql
CREATE TABLE employees (
  id          INT           PRIMARY KEY
                             AUTO_INCREMENT,
  first_name  VARCHAR(50)   NOT NULL,
  last_name   VARCHAR(50)   NOT NULL,
  email       VARCHAR(100)  UNIQUE NOT NULL,
  salary      DECIMAL(10,2) DEFAULT 0.00,
  dept_id     INT,
  hire_date   DATE          DEFAULT (CURDATE()),
  is_active   BOOLEAN       DEFAULT TRUE,
  created_at  TIMESTAMP     DEFAULT NOW(),

  -- Foreign key constraint
  FOREIGN KEY (dept_id)
    REFERENCES departments(id)
    ON DELETE SET NULL
    ON UPDATE CASCADE
);
✏️
ALTER TABLE
Modify existing table structure — add, change or drop.
sql
-- Add a column
ALTER TABLE employees
  ADD COLUMN phone VARCHAR(20);

-- Modify column type / constraint
ALTER TABLE employees
  MODIFY COLUMN salary DECIMAL(12,2) NOT NULL;

-- Rename a column
ALTER TABLE employees
  RENAME COLUMN phone TO mobile;

-- Drop a column
ALTER TABLE employees
  DROP COLUMN mobile;

-- Add a constraint
ALTER TABLE employees
  ADD CONSTRAINT chk_salary
  CHECK (salary >= 0);

-- Rename the table
ALTER TABLE employees
  RENAME TO staff;
🗑️
DROP, TRUNCATE & Constraints
Remove tables, clear data, and manage table-level constraints.
sql
-- DROP TABLE (permanent!)
DROP TABLE employees;
DROP TABLE IF EXISTS employees;

-- TRUNCATE: delete all rows fast
TRUNCATE TABLE employees;
-- Resets AUTO_INCREMENT; faster than DELETE

-- Drop database
DROP DATABASE mydb;

-- Constraint types summary
-- PRIMARY KEY  — unique, not null identifier
-- FOREIGN KEY  — reference to another table
-- UNIQUE       — no duplicate values
-- NOT NULL     — value required
-- DEFAULT      — fallback value
-- CHECK        — custom validation rule

-- Create table from SELECT
CREATE TABLE emp_backup
  AS SELECT * FROM employees;
Data Management

DML — Data Manipulation Language

INSERT, UPDATE and DELETE rows — the bread-and-butter of day-to-day database operations.

INSERT
Add single or multiple rows into a table.
sql
-- Single row
INSERT INTO employees
  (first_name, last_name, salary, dept_id)
VALUES
  ('Alice', 'Brown', 72000, 3);

-- Multiple rows
INSERT INTO employees
  (first_name, last_name, salary)
VALUES
  ('Bob',   'Smith', 68000),
  ('Carol', 'Jones', 75000),
  ('Dave',  'Lee',   80000);

-- Insert from SELECT
INSERT INTO archive
SELECT * FROM employees
WHERE is_active = 0;

-- UPSERT: insert or update on duplicate
INSERT INTO employees (id, salary)
VALUES (1, 85000)
ON DUPLICATE KEY UPDATE
  salary = VALUES(salary);
✏️
UPDATE
Modify existing rows — always use WHERE or update ALL rows.
sql
-- Update a single column
UPDATE employees
SET   salary = 90000
WHERE id = 42;

-- Update multiple columns
UPDATE employees
SET
  salary    = salary * 1.10,  -- 10% raise
  is_active = TRUE
WHERE department = 'Sales';

-- Update using subquery
UPDATE employees
SET salary = (
  SELECT AVG(salary) FROM benchmarks
  WHERE  role = 'dev'
)
WHERE title = 'Developer';

-- ⚠️ Update ALL rows (no WHERE)
UPDATE products
SET tax_rate = 0.18;  -- every row!
🗑️
DELETE
Remove rows from a table — with or without conditions.
sql
-- Delete specific rows
DELETE FROM employees
WHERE id = 42;

-- Delete with condition
DELETE FROM employees
WHERE hire_date < '2010-01-01'
  AND is_active = 0;

-- Delete using subquery
DELETE FROM orders
WHERE customer_id IN (
  SELECT id FROM customers
  WHERE  country = 'Deleted'
);

-- ⚠️ Delete ALL rows (dangerous)
DELETE FROM logs;   -- no WHERE = all rows

-- Safe delete: check count first
SELECT COUNT(*) FROM employees
WHERE dept_id = 7; -- then DELETE
Advanced Analytics

Window Functions

Perform calculations across a set of rows related to the current row without collapsing them like GROUP BY.

🪟
OVER() & PARTITION BY
Define the window frame and partition data into groups.
sql
-- Aggregate over entire result set
SELECT
  name, salary,
  AVG(salary) OVER()  AS company_avg
FROM employees;

-- PARTITION BY: per-group window
SELECT
  name, department, salary,
  AVG(salary)  OVER (PARTITION BY department)
                AS dept_avg,
  MAX(salary)  OVER (PARTITION BY department)
                AS dept_max
FROM employees;

-- Running total with ORDER BY in OVER
SELECT
  order_date, amount,
  SUM(amount) OVER (
    ORDER BY order_date
    ROWS BETWEEN UNBOUNDED PRECEDING
             AND CURRENT ROW
  ) AS running_total
FROM orders;
🏅
Ranking & Offset Functions
ROW_NUMBER, RANK, DENSE_RANK, LAG and LEAD.
sql
SELECT
  name, department, salary,

  -- ROW_NUMBER: unique 1,2,3...
  ROW_NUMBER() OVER (
    PARTITION BY department
    ORDER BY salary DESC
  ) AS row_num,

  -- RANK: gaps after ties (1,2,2,4)
  RANK() OVER (
    PARTITION BY dept
    ORDER BY salary DESC
  ) AS rank_num,

  -- DENSE_RANK: no gaps (1,2,2,3)
  DENSE_RANK() OVER (
    ORDER BY salary DESC
  ) AS dense,

  -- LAG/LEAD: previous/next row value
  LAG(salary, 1, 0) OVER (ORDER BY id) AS prev_sal,
  LEAD(salary, 1)    OVER (ORDER BY id) AS next_sal

FROM employees;
Performance

Indexes & Performance

Speed up queries dramatically with indexes — and understand EXPLAIN to diagnose slow queries.

CREATE & DROP INDEX
Index syntax and common index patterns.
sql
-- Create a regular index
CREATE INDEX idx_email
  ON employees(email);

-- Unique index
CREATE UNIQUE INDEX idx_emp_email
  ON employees(email);

-- Composite (multi-column) index
CREATE INDEX idx_dept_salary
  ON employees(department, salary);

-- Full-text index (MySQL)
CREATE FULLTEXT INDEX idx_bio
  ON employees(bio);

-- List indexes on a table
SHOW INDEX FROM employees;

-- Drop an index
DROP INDEX idx_email ON employees;

-- EXPLAIN: see query execution plan
EXPLAIN SELECT * FROM employees
WHERE email = 'a@b.com';
📈
Performance Tips & VIEWs
Query optimisation best practices and virtual table syntax.
sql
-- CREATE VIEW: saved query as virtual table
CREATE VIEW v_active_employees AS
  SELECT id, name, department, salary
  FROM   employees
  WHERE  is_active = 1;

-- Query a view like a table
SELECT * FROM v_active_employees;

-- Drop a view
DROP VIEW IF EXISTS v_active_employees;

-- Performance tips:
-- ✓ Index WHERE, JOIN, ORDER BY columns
-- ✓ Use LIMIT to avoid full scans
-- ✓ Avoid SELECT * in production
-- ✓ Use EXISTS over IN for large sets
-- ✓ Avoid functions on indexed columns
--   WHERE YEAR(date) = 2024  ← slow
--   WHERE date >= '2024-01-01' ← fast
-- ✓ Use covering indexes for hot queries
Programmability

Stored Procedures & Functions

Encapsulate reusable SQL logic on the server — procedures for actions, functions for return values.

⚙️
Stored Procedures
Create, call and drop reusable SQL routines with parameters.
sql
-- Create a stored procedure
DELIMITER //

CREATE PROCEDURE GetEmpByDept(
  IN  p_dept    VARCHAR(50),
  OUT p_count   INT
)
BEGIN
  SELECT * FROM employees
  WHERE department = p_dept;

  SELECT COUNT(*) INTO p_count
  FROM employees
  WHERE department = p_dept;
END //

DELIMITER ;

-- Call a procedure
CALL GetEmpByDept('Engineering', @cnt);
SELECT @cnt;

-- Drop a procedure
DROP PROCEDURE IF EXISTS GetEmpByDept;
🔣
User-Defined Functions & Triggers
Functions that return a value, and triggers that fire on events.
sql
-- User-defined function
DELIMITER //
CREATE FUNCTION CalcBonus(p_salary DECIMAL(10,2))
RETURNS DECIMAL(10,2) DETERMINISTIC
BEGIN
  RETURN p_salary * 0.15;
END //
DELIMITER ;

-- Use function in query
SELECT name, salary,
  CalcBonus(salary) AS bonus
FROM employees;

-- CREATE TRIGGER
CREATE TRIGGER before_emp_update
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
  SET NEW.updated_at = NOW();
END;
Data Integrity

Transactions & Locking

Group multiple statements into atomic units that either fully succeed or fully roll back — ACID compliance.

💳
Transaction Control
START, COMMIT, ROLLBACK and SAVEPOINT.
sql
-- Basic transaction
START TRANSACTION;  -- or BEGIN;

UPDATE accounts
  SET balance = balance - 500
  WHERE id = 1;

UPDATE accounts
  SET balance = balance + 500
  WHERE id = 2;

COMMIT;   -- save both or neither

-- Rollback on error
START TRANSACTION;
  DELETE FROM orders WHERE id = 5;
ROLLBACK;  -- undo everything

-- SAVEPOINT: partial rollback
SAVEPOINT sp1;
  -- do some work
ROLLBACK TO SAVEPOINT sp1;
RELEASE SAVEPOINT sp1;
🔒
ACID & Isolation Levels
Understanding ACID properties and transaction isolation.
ACID Property Meaning
Atomicity All or nothing — no partial commits
Consistency DB always goes from valid state to valid state
Isolation Concurrent txns don't interfere
Durability Committed data survives crashes
sql
-- Set isolation level
SET TRANSACTION ISOLATION LEVEL
  READ UNCOMMITTED;  -- lowest
  READ COMMITTED;
  REPEATABLE READ;   -- MySQL default
  SERIALIZABLE;      -- highest

-- Row locking
SELECT * FROM accounts
WHERE id = 1
FOR UPDATE;        -- exclusive lock

SELECT * FROM accounts
FOR SHARE;         -- shared/read lock
Pro Tips

Advanced SQL

String & date functions, UNION, INTERSECT, EXCEPT, recursive CTEs and useful built-in functions.

📝
String Functions
Manipulate and transform text columns in queries.
sql
UPPER('hello')         -- HELLO
LOWER('WORLD')         -- world
LENGTH('SQL')          -- 3
TRIM('  hi  ')         -- 'hi'
LTRIM / RTRIM          -- left/right trim

SUBSTRING('hello', 2, 3)   -- 'ell'
LEFT('hello', 3)            -- 'hel'
RIGHT('hello', 2)           -- 'lo'

CONCAT('a', 'b', 'c')      -- 'abc'
CONCAT_WS('-', 'a', 'b')  -- 'a-b'
REPLACE('ab', 'a', 'x')   -- 'xb'
INSTR('hello', 'll')       -- 3
LPAD('5', 3, '0')          -- '005'
REVERSE('abc')             -- 'cba'
FORMAT(1234567.8, 2)       -- '1,234,567.80'
📅
Date & Time Functions
Work with dates, times and intervals in SQL.
sql
NOW()                   -- 2024-06-01 12:30:00
CURDATE()               -- 2024-06-01
CURTIME()               -- 12:30:00

DATE(NOW())              -- extract date part
YEAR(hire_date)          -- 2022
MONTH(hire_date)         -- 6
DAY(hire_date)           -- 15
DAYNAME(hire_date)       -- Monday

DATEDIFF(NOW(), hire_date) -- days diff
TIMESTAMPDIFF(MONTH,
  hire_date, NOW())       -- months diff

DATE_ADD(NOW(),
  INTERVAL 30 DAY)        -- add 30 days
DATE_FORMAT(NOW(),
  '%d/%m/%Y')             -- 01/06/2024
🔀
UNION, INTERSECT & EXCEPT
Combine or compare result sets from multiple SELECT queries.
sql
-- UNION: combine, remove duplicates
SELECT id, name FROM customers
UNION
SELECT id, name FROM suppliers;

-- UNION ALL: keep duplicates (faster)
SELECT city FROM customers
UNION ALL
SELECT city FROM employees;

-- INTERSECT: rows in BOTH queries
SELECT email FROM customers
INTERSECT
SELECT email FROM newsletter;

-- EXCEPT / MINUS: in first but not second
SELECT email FROM customers
EXCEPT  -- use MINUS in Oracle
SELECT email FROM unsubscribed;

-- Rules: same # columns, compatible types

⚡ Built-in Functions Quick Reference

  • COALESCE(a,b,c)Return first non-NULL value
  • NULLIF(a, b)Return NULL if a equals b
  • IFNULL(val, def)Return def if val is NULL
  • IF(cond, t, f)Inline conditional expression
  • ROUND(n, d)Round to d decimal places
  • FLOOR(n)Round down to integer
  • CEIL(n)Round up to integer
  • ABS(n)Absolute value
  • CAST(val AS type)Convert to a different data type
  • CONVERT(val, type)Alternative type conversion (MySQL)
  • UUID()Generate a unique identifier
  • MD5(str)Return MD5 hash of string
More Resources

Explore More Cheat Sheets

Level up further with our other free developer reference guides and learning resources.

Download Your Free SQL Quick Guide PDF

Join 50,000+ developers who download our cheat sheets every month. Get the PDF link in your inbox instantly.

Join WhatsApp Channel