Theme A · Databases · SL & HL (with HL extensions)
A3.3.1 – A3.3.6
A3.3.4–A3.3.6 are HL only
Outline · Construct · Explain · Describe
SL: 11 hours (A3 total)
HL: 18 hours (A3 total)
How do we use SQL to retrieve, manipulate and protect the data inside a relational database?
Languages of SQL
Recognise the four sub-languages: DDL, DML, DCL and TCL — each has its own purpose.
Reading Data
SELECT queries with filtering, joining, grouping and ordering across two or more tables.
Modifying Data
INSERT, UPDATE and DELETE — and how indexes affect performance when data changes.
Reporting HL
Aggregate functions and views support analytics, security and abstraction.
Protecting Integrity HL
Transactions and ACID guarantees keep data correct even when things go wrong.
SQL is not one single language — it is a family of sub-languages, each with a distinct purpose. The IB syllabus focuses on DDL and DML, but you should also recognise DCL and TCL.
Defines and modifies the structure of the database — tables, columns, keys, indexes. It changes the schema, not the data.
Works with the data stored inside existing tables — retrieving, adding, modifying or removing rows. It does not change the schema.
Manages permissions — who can do what. Commands: GRANT, REVOKE.
Manages transactions — covered in A3.3.6 (HL). Commands: BEGIN TRANSACTION, COMMIT, ROLLBACK.
Exam tip: "Outline" needs only a brief description — name each language type, state its purpose (structure vs data) and give one or two example commands.
Student
| StudentID | Name | Year | CourseID |
|---|---|---|---|
| 101 | Aisha | 12 | CS01 |
| 102 | Ben | 12 | MA02 |
| 103 | Chen | 11 | CS01 |
| 104 | Dev | 13 | PH03 |
| 105 | Ella | 12 | NULL |
Course
| CourseID | Title | Credits |
|---|---|---|
| CS01 | Computer Science | 6 |
| MA02 | Mathematics | 6 |
| PH03 | Physics | 5 |
| BI04 | Biology | 5 |
SELECT * returns every column. Use it sparingly — name columns explicitly in production queries.
First sort by Year (highest first); within the same year, sort by Name alphabetically.
ASC = ascending (default, low → high). DESC = descending (high → low).
| CourseID | NumStudents |
|---|---|
| CS01 | 2 |
| MA02 | 1 |
| PH03 | 1 |
Rule: Every column in SELECT must either appear in GROUP BY or be inside an aggregate function.
| WHERE | HAVING |
|---|---|
| Filters rows before grouping | Filters groups after grouping |
| Cannot use aggregate functions | Can use aggregate functions |
| Used with single-row data | Used with grouped data |
Logical processing order: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
A JOIN combines rows from two tables based on a related column (usually a primary key in one table matching a foreign key in the other). This is the heart of A3.3.2 — "queries between two tables".
| Type | Returns |
|---|---|
| INNER | Only rows where the join condition is true in BOTH tables |
| LEFT (OUTER) | All rows from left table; NULL where right has no match |
| RIGHT (OUTER) | All rows from right table; NULL where left has no match |
| FULL OUTER | All rows from both; NULL on whichever side has no match |
| Name | Title |
|---|---|
| Aisha | Computer Science |
| Ben | Mathematics |
| Chen | Computer Science |
| Dev | Physics |
Ella excluded — her CourseID is NULL. Biology excluded — no student is enrolled.
| Name | Title |
|---|---|
| Aisha | Computer Science |
| Ben | Mathematics |
| Chen | Computer Science |
| Dev | Physics |
| Ella | NULL |
Exam tip: Always use table aliases (S, C) when joining — they prevent ambiguous column errors when both tables have a column with the same name (e.g. CourseID).
⚠ Missing WHERE updates every row in the table — a classic and costly mistake.
An index is a separate data structure (often a B-tree) that lets the DBMS find rows quickly without scanning the whole table. But indexes have a cost: every INSERT, UPDATE or DELETE on an indexed column must also update the index.
SELECT faster but INSERT/UPDATE/DELETE slower| More indexes | Fewer indexes |
|---|---|
| Faster SELECT & JOIN | Faster writes |
| Slower writes | Slower reads |
| More disk space | Less disk space |
| Maintenance overhead | Minimal maintenance |
Rule of thumb: Index columns frequently used in WHERE, JOIN or ORDER BY — but avoid indexing columns that change very often.
An aggregate function takes many rows of input and returns a single summary value. They are the foundation of reporting and decision-making — turning raw rows into totals, averages, counts and extremes.
| Function | Purpose | Example |
|---|---|---|
| COUNT(*) | Number of rows | How many students? |
| SUM(col) | Total of numeric column | Total credits |
| AVG(col) | Mean of numeric column | Average credits per course |
| MIN(col) | Smallest value | Lowest year level |
| MAX(col) | Largest value | Highest year level |
NULL handling: All aggregates except COUNT(*) ignore NULL values. COUNT(column) ignores NULLs in that column; COUNT(*) counts every row.
| Total | AvgCr | MinCr | MaxCr |
|---|---|---|---|
| 4 | 5.5 | 5 | 6 |
| Year | NumStudents | First | Last |
|---|---|---|---|
| 11 | 1 | 103 | 103 |
| 12 | 3 | 101 | 105 |
| 13 | 1 | 104 | 104 |
Why this matters for reporting: Aggregates let a database answer business questions ("How many sales last week?", "What's the average order value?") in a single query — no application-side counting needed.
Common error: Mixing a non-aggregated column into a SELECT without putting it in GROUP BY. SELECT Name, COUNT(*) FROM Student; is invalid — Name varies per row, COUNT(*) returns one value.
A view is a stored, named query that behaves like a virtual table. Users SELECT from it as if it were a real table, but underneath the DBMS executes the saved query.
Stores only the query definition, not the data. Each time you query the view, the underlying SELECT is re-run, so results are always current.
Stores the query result as a physical copy. Reads are very fast, but the snapshot can become stale until refreshed.
Hide sensitive columns. A payroll view can expose Name and Department but not Salary or SSN.
A view of a 6-table JOIN looks like one simple table to the user — query simplification.
Everyone uses the same definition (e.g. "active customer") — no two reports calculate it differently.
If the underlying tables change, only the view definition needs updating — the apps using the view stay the same.
Materialised views pre-compute expensive joins/aggregates for fast reporting dashboards.
Views can be marked read-only; simple views may also allow INSERT/UPDATE that flow through to base tables.
A transaction is a logical unit of work — one or more SQL statements that must succeed or fail together. Transactions protect data integrity when many users access the database concurrently or when failures occur mid-operation.
"All or nothing". A transaction's statements are treated as a single indivisible unit. If any step fails, every change made so far is rolled back.
A transaction moves the database from one valid state to another, never violating rules (constraints, foreign keys, triggers). Bad transactions are aborted.
Concurrent transactions appear to run one at a time. The intermediate state of one is not visible to another, preventing dirty reads and lost updates.
Once COMMIT succeeds, the change is permanent — it survives power loss, crash or reboot, typically via the write-ahead log on non-volatile storage.
| Command | What it does |
|---|---|
| BEGIN TRANSACTION | Marks the start of a transaction |
| COMMIT | Permanently saves all changes since BEGIN |
| ROLLBACK | Undoes all changes since BEGIN — restores prior state |
| SAVEPOINT | Optional checkpoint inside a transaction to roll back partially |
If the system crashes between Step 1 and Step 2, Alice loses £100 but Bob never receives it. ACID transactions prevent this — both updates either commit together or both roll back.
| Operator | Meaning |
|---|---|
= <> < > <= >= | Equality & comparison (note: <> = not equal) |
BETWEEN x AND y | Inclusive range |
IN (a,b,c) | Matches any value in list |
LIKE '%abc%' | Pattern match (% = any chars) |
IS NULL / IS NOT NULL | Test for missing values |
AND / OR / NOT | Combine conditions |
1. FROM & JOIN → 2. WHERE → 3. GROUP BY → 4. HAVING → 5. SELECT → 6. DISTINCT → 7. ORDER BY
| Term | Definition |
|---|---|
| SQL | Structured Query Language — the standard language for creating, reading, updating and deleting data in a relational database |
| DDL | Data Definition Language — statements that define structure: CREATE, ALTER, DROP |
| DML | Data Manipulation Language — statements that manipulate data: INSERT, UPDATE, DELETE |
| TCL (HL) | Transaction Control Language — BEGIN TRANSACTION, COMMIT (save changes), ROLLBACK (undo changes) |
| JOIN | Combines rows from two or more tables based on a related column — INNER, LEFT, RIGHT, or FULL OUTER |
| Aggregate function (HL) | Summarises many rows into one value — COUNT, SUM, AVG, MIN, MAX |
| GROUP BY / HAVING | Groups rows sharing a value, then filters those groups (HAVING filters after grouping; WHERE filters before) |
| View (HL) | A saved, virtual table defined by a query — always reflects live data; a materialized view stores a physical snapshot instead |
| Transaction | A group of database operations treated as a single all-or-nothing unit |
UPDATE Student SET Year = 13; changes every student. Always include a WHERE clause unless you genuinely intend a bulk operation.
Use WHERE to filter rows before aggregation, HAVING to filter the result of aggregation. WHERE COUNT(*) > 5 is invalid.
An INNER JOIN without an ON clause produces a Cartesian product — every row in A paired with every row in B (e.g. 1000 × 500 = 500,000 rows!).
WHERE col = NULL never matches anything. Use IS NULL / IS NOT NULL.
Use single quotes for string literals: 'Aisha'. Double quotes are reserved for identifiers in many DBMSs.
FROM Student S INNER JOIN Course C ON S.CourseID = C.CourseID — keeps column references unambiguous and queries readable.
If a question says "list all customers, including those with no orders", that signals a LEFT JOIN (keep all on the left). "Customers and their orders" usually means INNER JOIN.
| Term | Expected response |
|---|---|
| Outline | Brief overview, no detail required |
| Construct | Write the SQL statement |
| Explain | Reasons / causes / consequences |
| Describe | Detailed account, no need to justify |
Minor syntax variations between DBMSs are tolerated. Examiners look for correct logic and structure — not whether you ended every statement with a semicolon. Always use uppercase keywords for clarity.
Use the Student and Course tables from earlier slides.
Award 2 marks per property (define + link to scenario):
🔗 How does the schema design from A3.2 (primary keys, foreign keys, normalisation to 3NF) make the JOINs in A3.3 possible and efficient?
🌐 How might network latency (A2) affect the performance of multi-table JOINs in a distributed database, and how could materialised views help?
🤔 To what extent does the move toward NoSQL (A3.4 HL) compromise the ACID guarantees that relational databases provide? (TOK)
💡 How do indexes (A3.3.3) and views (A3.3.5) represent the same fundamental trade-off — pre-compute work to speed up reads, at the cost of storage and freshness?
NoSQL families — document, key-value, column-family, graph. OLTP vs OLAP. Data warehouses, ETL, and when relational is the wrong choice.
Building on data fundamentals — how databases feed training pipelines and how queries become features for models.
SQL is the universal language for working with relational data. Mastering SELECT (with JOINs, WHERE, GROUP BY) lets you ask any question; INSERT/UPDATE/DELETE lets you change the data safely; and ACID transactions guarantee that — no matter what goes wrong — your data stays correct.