Relational model
E. F. Codd published the relational model that became foundational to modern relational database systems.
One interactive reference for SQL fundamentals, commands, clauses, joins, functions, subqueries, CTEs, windows, transactions, database design, applications and the history of the language.
SQL grew from the relational model and IBM research in the 1970s, then became standardized and widely implemented across relational database systems.
E. F. Codd published the relational model that became foundational to modern relational database systems.
IBM researchers Donald Chamberlin and Raymond Boyce published work on SEQUEL, the predecessor of SQL.
Relational Software, later Oracle, developed and commercially shipped a relational SQL implementation.
IBM shipped DB2, helping establish SQL-based relational databases in enterprise computing.
ANSI standardized SQL in 1986; ISO followed with an SQL standard in 1987.
The SQL standard was substantially expanded, including richer query and data-definition capabilities.
Later revisions added features such as recursive queries, windowing and richer data capabilities.
SQL:2023 is the current standard referenced by the University of Edinburgh's 2026 database course material.
SQL becomes easier when tables, keys, relationships, schemas and constraints are treated as a system rather than isolated syntax.
A structured collection of data managed by a database system.
A relation made of rows and columns.
One record or tuple in a table.
An attribute describing one property of each record.
A column or column set that uniquely identifies rows.
A reference that connects a row to another table.
The logical structure that defines tables, relationships, constraints and other database objects.
A rule that protects data integrity, such as NOT NULL, UNIQUE or CHECK.
Build a mental model before memorizing syntax. These fundamentals explain how SQL statements are structured and how a relational database interprets them.
SQL (Structured Query Language) is used to define, query, manipulate and control data in relational database systems.
SELECT name FROM employees;
A SQL statement is an instruction sent to the database. A query usually describes a request for data, most commonly a SELECT statement.
SELECT name, salary FROM employees WHERE salary > 50000;
A SELECT query is commonly reasoned about as FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT.
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
NULL means an unknown or missing value. Use IS NULL or IS NOT NULL instead of = NULL.
SELECT * FROM employees WHERE manager_id IS NULL;
Aliases make long table and column references easier to read, especially in JOINs and calculated expressions.
SELECT e.name AS employee_name FROM employees AS e;
Use =, <>, >, <, >=, <= and logical operators such as AND, OR and NOT to express conditions.
SELECT * FROM shop WHERE price > 1000 AND stock >= 10;
Relational databases commonly use numeric, character, date/time and boolean-like types. Exact names vary by database engine.
CREATE TABLE users (id INT, name VARCHAR(100), joined_at DATE);
Aggregate functions reduce multiple rows into summaries. GROUP BY defines which rows belong to each group.
SELECT department_id, AVG(salary) FROM employees GROUP BY department_id;
SQL statements are commonly discussed by the kind of work they perform: reading data, changing rows, defining structure and controlling access or transactions.
Retrieve columns and expressions.
SELECT name, salary FROM employees;
Filter rows before grouping.
SELECT * FROM employees WHERE salary > 50000;
Sort the result.
SELECT * FROM employees ORDER BY salary DESC;
Remove duplicate result rows.
SELECT DISTINCT department FROM employees;
Restrict the number of rows returned.
SELECT * FROM employees LIMIT 10;
Add new rows.
INSERT INTO employees (name, salary) VALUES ('Asha', 60000);Change existing rows.
UPDATE employees SET salary = 65000 WHERE id = 7;
Remove rows.
DELETE FROM employees WHERE id = 7;
Combine insert/update logic where supported.
MERGE INTO target USING source ON target.id = source.id ...;
Create database objects.
CREATE TABLE employees (id INT PRIMARY KEY, name VARCHAR(100));
Change an existing object.
ALTER TABLE employees ADD COLUMN email VARCHAR(200);
Remove an object.
DROP TABLE old_employees;
Remove all rows while retaining the table structure.
TRUNCATE TABLE staging;
Give privileges.
GRANT SELECT ON employees TO analyst;
Remove privileges.
REVOKE UPDATE ON employees FROM analyst;
Make a transaction's changes durable.
COMMIT;
Undo uncommitted transaction work.
ROLLBACK;
Create a transaction rollback point.
SAVEPOINT before_update;
Choose the source table(s).
FROM employees
Combine related rows from multiple tables.
JOIN departments d ON e.department_id = d.id
Filter individual source rows.
WHERE salary >= 50000
Form groups for aggregate calculations.
GROUP BY department_id
Filter groups after aggregation.
HAVING AVG(salary) > 60000
Choose the final expressions/columns.
SELECT department_id, AVG(salary)
Remove duplicate final rows.
SELECT DISTINCT city
Sort the result.
ORDER BY AVG(salary) DESC
Restrict returned rows where supported.
LIMIT 10
SELECT
d.name AS department,
COUNT(*) AS people,
AVG(e.salary) AS avg_salary
FROM employees e
JOIN departments d
ON e.department_id = d.id
WHERE e.active = TRUE
GROUP BY d.name
HAVING AVG(e.salary) > 50000
ORDER BY avg_salary DESC;A JOIN combines rows from multiple table expressions according to a matching condition or join rule.
Only matching rows from both sides.
SELECT e.name, d.name FROM employees e INNER JOIN departments d ON e.department_id = d.id;
All rows from the left table plus matching rows on the right.
SELECT e.name, d.name FROM employees e LEFT JOIN departments d ON e.department_id = d.id;
All rows from the right table plus matching rows on the left.
SELECT e.name, d.name FROM employees e RIGHT JOIN departments d ON e.department_id = d.id;
All rows from both sides, matched where possible.
SELECT * FROM A FULL OUTER JOIN B ON A.id = B.id;
Cartesian product: every left row paired with every right row.
SELECT * FROM colors CROSS JOIN sizes;
Join a table to itself using aliases.
SELECT e.name, m.name FROM employees e JOIN employees m ON e.manager_id = m.id;
Expressions let a query calculate, transform and classify values while returning or updating data.
Count rows or non-null values.
COUNT(*)
Add numeric values.
SUM(amount)
Calculate an average.
AVG(salary)
Find the smallest value.
MIN(price)
Find the largest value.
MAX(price)
Return the first non-null expression.
COALESCE(phone, 'N/A')
Return NULL when two expressions are equal.
NULLIF(score, 0)
Implement conditional expressions.
CASE WHEN salary > 80000 THEN 'Senior' ELSE 'Other' END
Advanced SQL combines query composition, analytics, reusable definitions, integrity and performance techniques.
A query nested inside another query.
SELECT name FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
Named query blocks introduced with WITH, useful for readable multi-step logic.
WITH high_paid AS (...) SELECT * FROM high_paid;
Calculate across related rows without collapsing them into groups.
AVG(salary) OVER (PARTITION BY department_id)
Combine compatible query results.
SELECT city FROM customers UNION SELECT city FROM suppliers;
Store a reusable query definition as a database object.
CREATE VIEW active_users AS SELECT ...;
Data structures that can accelerate selected access patterns, with storage/write trade-offs.
CREATE INDEX idx_email ON users(email);
Group multiple changes into an atomic unit of work.
BEGIN; UPDATE ...; COMMIT;
Enforce integrity at the database layer.
CHECK (salary >= 0)
Server-side routines supported by many SQL database systems.
CREATE PROCEDURE ...
Database actions automatically invoked by defined events where supported.
CREATE TRIGGER ...
Database design affects correctness, maintainability and query performance. Learn normalization, keys, constraints and indexing before optimizing syntax.
Reduce inappropriate redundancy and update anomalies by structuring related data.
Atomic values and a tabular structure without repeating groups.
1NF plus removal of partial dependency on a composite key.
2NF plus removal of relevant transitive dependencies.
Speed selected reads by maintaining additional access structures at storage cost.
Use atomic units of work with COMMIT and ROLLBACK semantics.
Atomicity, consistency, isolation and durability are core transaction properties.
The database optimizer chooses an execution strategy based on statistics, indexes and other factors.
Relational databases are used across application development, finance, commerce, analytics, engineering and many operational systems.
Users, authentication records, products, orders, subscriptions and application state.
Accounts, transactions, ledgers, payments, compliance and reporting.
Catalogs, inventory, carts, orders, customers, pricing and fulfillment.
Dashboards, KPIs, aggregations, cohort analysis and business reporting.
ETL/ELT pipelines, staging tables, transformations and data quality checks.
Feature extraction, dataset preparation, exploration and analytical workloads.
Structured records, scheduling, billing, inventory and operational reporting, subject to applicable privacy controls.
Students, courses, assessments, attendance, learning activity and reporting.
Routes, shipments, warehouses, drivers, inventory and delivery events.
Players, inventories, scores, sessions, purchases and game telemetry.
Use this sequence as a practical route from basic retrieval to production database thinking.
SQLWhale turns query execution into a visual learning process. Write a query, run it and follow what happens to the data.
Open SQLWhale Query Lab →