E ExamMaster

CS Core & Software Engineering · Databases

Relations, Keys and Basic SQL

What a relation is, how keys name a row, relational algebra, and SELECT/WHERE on one campus-shop table.

Same campus kiosk. A relation is a table of facts; a key names a row; algebra and SQL are two spellings of "keep these rows, keep these columns". Joins, grouping and NULL wait in the next lesson — we learn to read one table first.

  • CS Core & Software Engineering
  • Medium level
  • 5 concepts
  • 1 practice questions

1A relation is a table of facts

A relation is a table whose rows are facts of the same kind and whose columns are named attributes. Sale is a relation: every row is one purchase, and every row has sale_id, student_id, item_id and qty. The heading (those four names) is the schema. The four purchase rows are the instance — the facts that happen to be true today.

Order of rows does not change the relation. Sale listed 103 first is the same Sale. Duplicate rows are not a second fact in the pure model: a set does not contain the same tuple twice. SQL will later keep duplicates unless we ask it not to. That gap between the model and SQL is why we name both.

Figure. Four Sale rows at the campus kiosk: sale_id, who bought, what, how many.

Read Sale as a relation

  1. Schemasale_id, student_id, item_id, qty — the attributes every sale must have.
  2. InstanceThe four rows 100–103 that are true at the kiosk today.
  3. Set vs SQLAlgebra treats rows as a set; SQL SELECT keeps a duplicate until DISTINCT.
Sale today
sale_idstudent_iditem_idqty
1001102
1012111
1021121
1033113
If we print Sale with row 103 at the top, we have
  1. A different relation, because order is part of the data
  2. The same relation: row order is not part of a relation
  3. An illegal table, because sale_id must increase

A relation is a set of tuples. Display order is not a fact in the model.

2Keys: which column identifies a row

A key is a column (or a small set of columns) that names a row so we can find it again. sale_id 100 is enough to mean "Asha's two samosas" and nothing else. That is a primary key: unique, never empty, the official handle of the row. student_id is the primary key of Student; item_id is the primary key of Item.

A foreign key is a copy of someone else's primary key, stored so a row can point. Sale.student_id = 1 means "this sale belongs to the Student whose key is 1" — Asha. It is not a second primary key of Sale. Two sales can share student_id 1; they must not share sale_id.

Figure. Sale has one primary key and two foreign keys. The arrows land on the tables those ids name.

Keys on the three tables

  1. Primary on Salesale_id is unique: 100, 101, 102, 103.
  2. Primary on the nounsStudent.student_id; Item.item_id.
  3. Foreign on Salestudent_id and item_id point; they may repeat (Asha appears twice).
Keys at the kiosk
ColumnKindMay repeat?
Sale.sale_idprimaryno
Sale.student_idforeign → Studentyes (Asha twice)
Sale.item_idforeign → Itemyes (Tea twice)
Student.student_idprimaryno
Asha appears on sale 100 and sale 102. That is legal because
  1. sale_id is allowed to repeat
  2. student_id is a foreign key and may repeat; sale_id still differs
  3. primary keys may repeat as long as the name is the same

The primary key of Sale is sale_id (100 vs 102). student_id is a pointer and is allowed to repeat.

3Relational algebra core operators

Relational algebra is a closed kit of operators: each one takes relations and returns a relation. Selection \sigma keeps rows that satisfy a condition — \sigma_{\text{item\_id}=11}(\text{Sale}) is the two tea sales. Projection \pi keeps named columns — \pi_{\text{student\_id}}(\text{Sale}) is the buyer ids. Union, difference, Cartesian product and rename complete the primitives.

A join is not a sixth primitive. It is product (every Sale row paired with every Item row), then selection on the matching ids, then projection to drop the duplicated item_id. SQL's FROM / WHERE / SELECT is the same three moves with different spelling.

Figure. Select filters rows, project keeps columns, join is built from those primitives — not a new primitive.

Tea sales from primitives

  1. Select\sigma_{\text{item\_id}=11}(\text{Sale}) keeps rows 101 and 103.
  2. Project\pi_{\text{student\_id, qty}} on that result keeps (2,1) and (3,3).
  3. Join laterPairing Sale with Item is product + select on item_id + project.
Core operators
OperatorActs onOn this shop
\sigma_c(R)rowstea sales: item_id = 11
\pi_A(R)columnsjust student_id from Sale
R \times Stwo relationsevery Sale paired with every Item
R \cup S, R - Ssets of rowsschemas must match
\rhonamessame rows, new name

Select the tea sales

Sale has four rows. How many rows does \sigma_{\text{item\_id}=11}(\text{Sale}) return, and which sale_ids?

  • rows in Sale4
  • rows with item_id = 11101 and 103
  • |\sigma_{item\_id=11}(Sale)|2

Pro tip. Selection never invents rows; it only keeps the ones that already match.

In pure relational algebra, a natural join R \bowtie S is best described as
  1. A sixth primitive operator, independent of product and selection
  2. A composition of product, selection on common attributes, and projection that removes duplicate columns
  3. Only a projection of R, because S contributes no rows

Natural join is derived: R \times S, then \sigma on equality of shared attributes, then \pi to drop the duplicated columns.

4SELECT and WHERE on Sale

SQL is the language we type to ask a relation a question. SELECT names the columns we want back. FROM names the table we start from. WHERE names the row test. "Which sales are tea?" is: look at Sale, keep rows whose item_id is 11, return sale_id and qty.

WHERE runs on each row by itself. It cannot see a total across rows — that needs grouping, in the next lesson. It also cannot see a column we invent in SELECT (an alias), because WHERE happens before SELECT computes output names.

Figure. FROM starts with four Sale rows. WHERE item_id = 11 keeps the two tea rows.

Ask Sale for the tea rows

  1. FROMStart with the Sale table — all four purchases.
  2. WHEREKeep the rows where item_id = 11 (101 and 103).
  3. SELECTReturn sale_id and qty for those two rows.

Tea sales at the kiosk

SELECT sale_id, qty
FROM sale
WHERE item_id = 11;
-- rows: (101, 1) and (103, 3)

Filter then project

How many rows does the tea query return, and what is the sum of qty on those rows?

  • Sale rows4
  • WHERE item_id = 112 rows (101, 103)
  • qty 1 + qty 34 teas sold

Pro tip. WHERE shrinks rows; SELECT shrinks columns. Neither invents a sale.

Coding lab. Ask the kiosk for Asha's sales runs in the app, with checks on your output.

To list every sale by Asha (student_id = 1) we put student_id = 1 in
  1. SELECT, because that is where conditions go
  2. WHERE, because that is the per-row test
  3. FROM, because Asha is a table

FROM names Sale. WHERE keeps the rows whose student_id is 1. SELECT names the output columns.

5SQL logical query order

We write SELECT first, but the engine does not start there. Logical order is FROM (build the working table), then WHERE (row filters), then GROUP BY, then HAVING, then SELECT (output expressions and aliases), then ORDER BY. That is why an alias invented in SELECT is invisible to WHERE.

On the kiosk: FROM sale WHERE student_id = 1 SELECT sale_id works. FROM sale WHERE teas > 0 SELECT qty AS teas fails, because teas does not exist until SELECT runs. Put the test on qty in WHERE, or filter the alias in a later clause.

Figure. Written SELECT-first; evaluated FROM-first. Aliases appear only at step 4.

Logical evaluation order

  1. FROMResolve tables and joins into one working relation.
  2. WHERE → GROUP BY → HAVINGFilter rows, group them, then filter groups.
  3. SELECT → ORDER BYCompute output columns and aliases, then sort.

Skeleton showing clause roles

SELECT student_id, COUNT(*) AS n
FROM sale
WHERE qty > 0
GROUP BY student_id
HAVING COUNT(*) >= 1
ORDER BY n DESC;
Why can WHERE teas > 0 fail even when SELECT qty AS teas appears in the same query?
  1. WHERE runs before SELECT, so the alias teas does not exist yet
  2. Aliases are only allowed in FROM
  3. ORDER BY forbids aliases, so WHERE must too

Logically WHERE filters rows before SELECT computes output names. Test qty in WHERE, not the alias.

Notes

  • Relational algebra core operators: selection (\sigma, rows), projection (\pi, columns), union, set difference, Cartesian product, and rename; joins are derived.
  • SQL logical query order: FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY; WHERE filters rows, HAVING filters groups.
  • Joins: INNER JOIN keeps matching rows; LEFT/RIGHT OUTER JOIN keep all rows of one side; NULLs fill non-matches.
  • Aggregate functions (COUNT, SUM, AVG, MIN, MAX) ignore NULLs except COUNT(*); they are used with GROUP BY for per-group results.
  • A NULL represents unknown/missing data; comparisons with NULL yield UNKNOWN, so use IS NULL / IS NOT NULL, not = NULL.

Formulas

  • SELECT col FROM table WHERE condition GROUP BY col HAVING agg_condition ORDER BY col;
  • \sigma_{condition}(R) selects rows; \pi_{columns}(R) projects columns.
  • Natural join R \bowtie S matches on all common attributes and removes duplicates.
  • COUNT(*) counts all rows including NULLs; COUNT(col) counts only non-NULL values of col.
  • DISTINCT removes duplicate rows; UNION removes duplicates while UNION ALL keeps them.

Exam traps & shortcuts

  • WHERE cannot use aggregate functions; put aggregate conditions in HAVING.
  • For 'at least one match, keep all left rows' use LEFT OUTER JOIN.
  • Projection in relational algebra removes duplicates automatically; SQL SELECT keeps them unless DISTINCT is used.

Reference tables

Sale schema versus instance
WordOn this shop
Schemasale_id, student_id, item_id, qty
Instancethe four rows 100–103
Primary keysale_id
Foreign keysstudent_id → Student, item_id → Item

Recap

One table, then a question.

Relation
Schema is the heading; instance is today's rows. Order does not matter.
Primary key
sale_id names a sale. It must not repeat.
Foreign key
student_id points at Student and may repeat (Asha twice).
Algebra
\sigma keeps rows, \pi keeps columns; join is product + select + project.
SQL
FROM then WHERE then SELECT. Aliases do not exist in WHERE.

Practise Relations, Keys and Basic SQL

Reading is free and needs no account. Practice, mocks and progress live in the app.

  • 1 exam-style questions on this topic, with explanations
  • A 2-question practice set that ends the chapter
  • Timed mocks scored with the real marking scheme
  • Readiness tracked per topic, kept on your device
Continue with Google — freeNo card, no trial. Works offline once installed.