SEN2104 · Week 4 · Relational Algebra

Relational algebra: basic operators

Writing queries with selection, projection, set operations, the Cartesian product and rename; the basis of the “write the relational algebra expression” and “give the result” exam questions.

relational algebraselectionprojectionunionset differenceintersectionCartesian productrenameunion-compatibleset semanticsquery tree

Relational algebra is a small set of operators that work on relations (tables) and whose result is again a relation. This is the mathematics behind SQL. The database engine first translates your SQL query into an expression like this, then optimizes it. The exam has two kinds of questions: “Write a relational algebra expression for …” and “Give the result of this expression”. For both, knowing the six fundamental operators on this page is enough.

Golden rules:

  1. σ selects rows, π selects columns. Whoever mixes them up loses the easiest points.
  2. Every result is a set. There are no repeated rows; π removes duplicates.
  3. ∪, −, ∩ are only done between union-compatible relations.
  4. × alone is almost never useful. A σ with the matching condition follows it.
  5. Read the expression from the inside out. The innermost parentheses are evaluated first.

The sample database

We use the same small university database all semester. These are the tables needed most on this page.

student

stu_idnamedept_nametot_cred
S1AdaCS60
S2BoraCS30
S3CemEE45
S4DefneMATH90
S5EceCS15
S6FiratEE0
S7GizemNULL10

course

course_idtitledept_namecredits
CS101Intro to ProgrammingCS4
CS201Data StructuresCS4
CS305DatabasesCS3
EE210CircuitsEE3
MA101CalculusMATH4
MA202Linear AlgebraMATH3
BI100BiologyBIO3

takes (S6 has taken no course, S3 has no grade yet for CS101)

stu_idcourse_idgrade
S1CS101A
S1CS201B
S1CS305A
S1MA101B
S2CS101B
S2CS201C
S3EE210A
S3MA101C
S3CS101NULL
S4MA101A
S4MA202A
S4CS305B
S5CS101F
S7MA202B

instructor and department

inst_idnamedept_namesalary
I1AksoyCS95000
I2DemirCS80000
I3KayaEE85000
I4SahinMATH70000
I5CelikMATH72000
I6YildizBIO60000
dept_namebuildingbudget
CSGalata500000
EEGalata350000
MATHRumeli200000
BIOKadikoy150000

teaches(inst_id, course_id): (I1, CS101), (I1, CS305), (I2, CS201), (I3, EE210), (I4, MA101), (I5, MA202). I6 teaches no course, and nobody teaches BI100.

Selection: σ

Selection σp(R)\sigma_{p}(R) returns the rows of RR that satisfy the condition pp. The columns stay as they are. The condition uses comparison operators (=,≠,<,≤,>,≥=, \neq, <, \le, >, \ge) and logical connectives (∧\land and, ∨\lor or, ¬\lnot not).

σdept_name=’CS’(student)\sigma_{dept\_name = \text{'CS'}}(student)

stu_idnamedept_nametot_cred
S1AdaCS60
S2BoraCS30
S5EceCS15

If two conditions concern the same row, they combine in a single selection: σdept_name=’CS’∧tot_cred>20(student)\sigma_{dept\_name = \text{'CS'} \land tot\_cred > 20}(student) gives S1 (Ada) and S2 (Bora).

The order of selections does not matter: σp(σq(R))=σq(σp(R))=σp∧q(R)\sigma_{p}(\sigma_{q}(R)) = \sigma_{q}(\sigma_{p}(R)) = \sigma_{p \land q}(R).

Projection: π

Projection πA1,…,Ak(R)\pi_{A_1, \dots, A_k}(R) keeps only the listed columns. Because a relation is a set, duplicate rows are removed.

πdept_name(student)\pi_{dept\_name}(student)

dept_name
CS
EE
MATH
NULL

There are 7 students but the result has 4 rows. In SQL, SELECT dept_name FROM student returns 7 rows; to get the same result as relational algebra you need to write SELECT DISTINCT. SQL uses multiset semantics, algebra uses set semantics.

PITFALL · π can reduce the number of rows. For a “How many tuples?” question, do not just count the table and move on. After a projection, count rows that look the same as one.

Composition

Since the result of every operator is a relation, operators can be nested. The names of instructors who earn more than 75000:

πname(σsalary>75000(instructor))={Aksoy,Demir,Kaya}\pi_{name}(\sigma_{salary > 75000}(instructor)) = \{\text{Aksoy}, \text{Demir}, \text{Kaya}\}

The order matters: first σ, then π. If you write the opposite (σsalary>75000(πname(instructor))\sigma_{salary > 75000}(\pi_{name}(instructor))), the expression is invalid, because after the projection the salary column no longer exists.

Set operations: ∪, −, ∩

All three require the two relations to be union-compatible:

  • the same degree (arity), that is, the same number of columns,
  • the domains of the iith columns are the same.

Column names do not have to be the same; the result takes the names of the left relation.

Let us work with the courses taken by S1 and S4: A=πcourse_id(σstu_id=’S1’(takes))A = \pi_{course\_id}(\sigma_{stu\_id = \text{'S1'}}(takes)) = {CS101, CS201, CS305, MA101}, B=πcourse_id(σstu_id=’S4’(takes))B = \pi_{course\_id}(\sigma_{stu\_id = \text{'S4'}}(takes)) = {MA101, MA202, CS305}.

ExpressionMeaningResult
A∪BA \cup Btaken by at least one of themCS101, CS201, CS305, MA101, MA202
A∩BA \cap Btaken by bothCS305, MA101
A−BA - Btaken by S1 but not by S4CS101, CS201
B−AB - Ataken by S4 but not by S1MA202

Difference is not commutative: A−B≠B−AA - B \neq B - A. Intersection is not counted as a fundamental operator, because it can be written with difference: A∩B=A−(A−B)A \cap B = A - (A - B).

“None” questions with difference. Courses that no student has taken:

πcourse_id(course)−πcourse_id(takes)={BI100}\pi_{course\_id}(course) - \pi_{course\_id}(takes) = \{\text{BI100}\}

Departments that have both students and instructors are an intersection: πdept_name(student)∩πdept_name(instructor)\pi_{dept\_name}(student) \cap \pi_{dept\_name}(instructor) = {CS, EE, MATH}. BIO has no students, and NULL has no instructors.

Cartesian product: ×

R×SR \times S puts each row of RR next to each row of SS. The number of rows is ∣R∣⋅∣S∣|R| \cdot |S|, the number of columns is the sum of the degrees. Columns with the same name are told apart by the table name.

instructor×departmentinstructor \times department: 6⋅4=246 \cdot 4 = 24 rows, 4+3=74 + 3 = 7 columns (instructor.dept_name and department.dept_name are separate).

Most of these 24 rows are meaningless: it pairs Aksoy with the BIO building. You keep the meaningful ones with a selection:

πname, building(σinstructor.dept_name=department.dept_name(instructor×department))\pi_{name,\, building}(\sigma_{instructor.dept\_name = department.dept\_name}(instructor \times department))

namebuilding
AksoyGalata
DemirGalata
KayaGalata
SahinRumeli
CelikRumeli
YildizKadikoy

Of the 24 rows, 6 remained, each instructor with their own department. This “multiply, then select by equality” pattern is the definition of a join. Next week we will abbreviate it with ⋈.

PITFALL · forgetting the matching condition. If you do not write a σ after the product, fake rows like “every instructor in every building” get into the result. In every expression with a product, ask “which column links the tables?”

Rename: ρ

ρx(E)\rho_{x}(E) gives the result of expression EE the name xx. ρx(A1,…,An)(E)\rho_{x(A_1, \dots, A_n)}(E) also renames the columns. Its real job: comparing a table with itself. Without giving the two copies different names, you cannot say which salary in instructor×instructorinstructor \times instructor comes from which copy.

Example: the highest salary (without aggregate functions). The idea: the highest salary is a salary for which no higher salary exists.

1) ρ_i(instructor) × ρ_j(instructor)          36 rows
2) σ_{i.salary < j.salary}(...)               there is a j that earns more than i
3) π_{i.salary}(...)                           = {80000, 85000, 70000, 72000, 60000}
4) π_salary(instructor) − (3)                  = {95000}

πsalary(instructor)−πi.salary(σi.salary<j.salary(ρi(instructor)×ρj(instructor)))={95000}\pi_{salary}(instructor) - \pi_{i.salary}(\sigma_{i.salary < j.salary}(\rho_{i}(instructor) \times \rho_{j}(instructor))) = \{95000\}

If you change the condition to >>, the same pattern gives the lowest salary (60000).

Fundamental and derived operators

There are six fundamental operators: σ,π,∪,−,×,ρ\sigma, \pi, \cup, -, \times, \rho. Every relational algebra query can be written with them. ∩\cap, joins and division are derived from these six; they are only shorthand.

OperatorKindInputDegree of result
σp(R)\sigma_{p}(R)unary1 relationdegree(R)
πL(R)\pi_{L}(R)unary1 relation∣L∣\lvert L \rvert
ρx(R)\rho_{x}(R)unary1 relationdegree(R)
R∪SR \cup S, R−SR - Sbinary2 compatible relationsdegree(R)
R×SR \times Sbinary2 relationsdegree(R) + degree(S)

Query tree

An expression is drawn as a tree: leaves are tables, inner nodes are operators, the root is the result. For the instructor building query:

              π name, building
                    |
   σ instructor.dept_name = department.dept_name
                    |
                    ×
                  /   \
         instructor   department

The tree is evaluated from bottom to top. In the optimization week (week 13) we will compare different trees of the same query and see why pushing σ below the product is cheap.

Method for solving questions

For a “Write the relational algebra” question, follow this order:

  1. Which tables are needed? If more than one, take the product and equate the linking columns.
  2. Put the row conditions in σ.
  3. Take the requested columns with π on the outside.
  4. If the question has “both / every / never / only”, you need a set operation: “both” → ∩, “never” → difference.

Example: the names of students who take courses outside their own department. Three tables are needed, two matching conditions and one inequality condition:

πs.name(σs.stu_id=t.stu_id∧t.course_id=c.course_id∧s.dept_name≠c.dept_name(ρs(student)×ρt(takes)×ρc(course)))\pi_{s.name}(\sigma_{s.stu\_id = t.stu\_id \land t.course\_id = c.course\_id \land s.dept\_name \neq c.dept\_name}(\rho_{s}(student) \times \rho_{t}(takes) \times \rho_{c}(course)))

The product has 7⋅14⋅7=6867 \cdot 14 \cdot 7 = 686 rows, and after the selection Ada, Cem and Defne remain. Because Gizem’s department is NULL, the ≠\neq comparison does not come out true and the row is dropped.

Common mistakes

Wrong ideaThe truth
π preserves the number of rowsIt removes duplicates; πbuilding(department)\pi_{building}(department) has 3 rows
For “took both”, σc=’X’∧c=’Y’\sigma_{c = \text{'X'} \land c = \text{'Y'}}A single row cannot take two values, so it returns empty. Build two sets, take ∩
First π, then σ on that columnπ does not bring back the column it dropped; write σ first
If both relations have the same number of columns, ∪ worksThe domains must also match in order
R−S=S−RR - S = S - RDifference is not commutative
The number of rows of R×SR \times S is ∣R∣+∣S∣\lvert R \rvert + \lvert S \rvertThey are multiplied: ∣R∣⋅∣S∣\lvert R \rvert \cdot \lvert S \rvert
ρ is not needed for a self-productThe names clash; separate the two copies with ρ
NULL ≠ ‘CS’ is trueEvery comparison with NULL is unknown, and the row is not selected

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

Give the result of πcourse_id(σcredits=4(course))\pi_{course\_id}(\sigma_{credits = 4}(course)) on the sample database.

Show answer
CS101, CS201, MA101

First the selection: the rows of the course table with credits = 4 are CS101, CS201 and MA101. Then the projection keeps only the course_id column. There are no repeats, so three rows remain.

Question 2easy

How many tuples and how many attributes does student×coursestudent \times course have?

Show answer
49 tuples, 8 attributes

In a Cartesian product the row counts are multiplied and the column counts are added. student has 7 rows and 4 columns, course has 7 rows and 4 columns. 7⋅7=497 \cdot 7 = 49 rows, 4+4=84 + 4 = 8 columns. Because both tables have dept_name, the result has two separate columns, student.dept_name and course.dept_name.

Question 3easy

Give the result of πbuilding(department)\pi_{building}(department). How many tuples does it have?

Show answer
Galata, Rumeli, Kadikoy (3 tuples)

department has 4 rows, but CS and EE are both in Galata. Relational algebra uses set semantics, and projection removes duplicates. The result has 3 rows, not 4: Galata, Rumeli, Kadikoy.

Question 4medium

Write a relational algebra expression that returns the names of instructors in the MATH department whose salary is greater than 71000. Give the result.

Show answer
π_name(σ_{dept_name='MATH' ∧ salary>71000}(instructor)) = Celik

Since both conditions concern the same row, they are combined with ∧\land in a single selection:πname(σdept_name=’MATH’∧salary>71000(instructor))\pi_{name}(\sigma_{dept\_name = \text{'MATH'} \land salary > 71000}(instructor)).
The MATH instructors are Sahin (70000) and Celik (72000). Only Celik is above 71000.

Question 5medium

Give the result of πcourse_id(course)−πcourse_id(teaches)\pi_{course\_id}(course) - \pi_{course\_id}(teaches). What does it mean in plain English?

Show answer
BI100 (courses that no instructor teaches)

The left set is all courses (7 courses). The right set is the courses that appear in teaches: CS101, CS305, CS201, EE210, MA101, MA202. The difference is what is on the left but not on the right: BI100. Meaning: courses that no instructor teaches.

Question 6medium

Write a relational algebra expression for the IDs of students who took both CS101 and MA101. Give the result.

Show answer
π_stu_id(σ_{course_id='CS101'}(takes)) ∩ π_stu_id(σ_{course_id='MA101'}(takes)) = S1, S3

Questions that ask for “both” cannot be solved with a single selection: σcourse_id=’CS101’∧course_id=’MA101’\sigma_{course\_id = \text{'CS101'} \land course\_id = \text{'MA101'}} returns empty, because the course_id value of one row cannot be two things at once. The right way is to build two separate sets and take the intersection.
Students who took CS101: S1, S2, S3, S5. Students who took MA101: S1, S3, S4. Intersection: S1, S3.

Question 7medium

Give the result of πstu_id(σcourse_id=’CS101’(takes))∪πstu_id(σcourse_id=’MA202’(takes))\pi_{stu\_id}(\sigma_{course\_id = \text{'CS101'}}(takes)) \cup \pi_{stu\_id}(\sigma_{course\_id = \text{'MA202'}}(takes)).

Show answer
S1, S2, S3, S4, S5, S7

Students who took CS101: S1, S2, S3, S5. Students who took MA202: S4, S7. The union collects both without repeats: S1, S2, S3, S4, S5, S7. The same query can also be written with a single selection: σcourse_id=’CS101’∨course_id=’MA202’\sigma_{course\_id = \text{'CS101'} \lor course\_id = \text{'MA202'}}.

Question 8medium

Is πstu_id, name(student)∪πcourse_id(course)\pi_{stu\_id,\, name}(student) \cup \pi_{course\_id}(course) a valid relational algebra expression? Why?

Show answer
No, not union-compatible (2 vs 1 attributes)

For union, difference and intersection, the two relations must be union-compatible: the same number of columns and, in order, the same kind of domain. The left side has 2 columns and the right side has 1. The expression is invalid. SQLite gives the same error: “do not have the same number of result columns”.

Question 9hard

Write a relational algebra expression that returns the IDs of students who have not taken any course. Give the result.

Show answer
π_stu_id(student) − π_stu_id(takes) = S6

The “never did ...” pattern is solved with difference: everyone minus those who did.πstu_id(student)\pi_{stu\_id}(student) = S1..S7. πstu_id(takes)\pi_{stu\_id}(takes) = S1, S2, S3, S4, S5, S7. Difference: S6 (Firat).

Question 10hard

Using only σ\sigma, π\pi, ×\times, −- and ρ\rho (no aggregation), write an expression for the lowest instructor salary. Give the result.

Show answer
π_salary(instructor) − π_i.salary(σ_{i.salary > j.salary}(ρ_i(instructor) × ρ_j(instructor))) = 60000

To multiply a table by itself, give the two copies different names: ρi(instructor)×ρj(instructor)\rho_i(instructor) \times \rho_j(instructor) (36 rows).σi.salary>j.salary\sigma_{i.salary > j.salary} keeps the rows where “someone earns less than this one”. Their i.salaryi.salary values cannot be the lowest.
Subtract these from all salaries: 60000 (Yildiz) remains.

Question 11hard

Using σ\sigma, π\pi, ×\times and ρ\rho, write an expression for the names of students who took at least one course offered by a department other than their own. Give the result on the sample data.

Show answer
Ada, Cem, Defne

Multiply the three tables and put the matching conditions and the different-department condition in the selection:πs.name(σs.stu_id=t.stu_id∧t.course_id=c.course_id∧s.dept_name≠c.dept_name(ρs(student)×ρt(takes)×ρc(course)))\pi_{s.name}(\sigma_{s.stu\_id = t.stu\_id \land t.course\_id = c.course\_id \land s.dept\_name \neq c.dept\_name}(\rho_s(student) \times \rho_t(takes) \times \rho_c(course))).
Ada (CS) took MA101, Cem (EE) took MA101 and CS101, Defne (MATH) took CS305. Gizem's department is NULL: a comparison with NULL does not count as true, so Gizem is not in the result.

Question 12easy

How many tuples does σgrade=’A’(takes)\sigma_{grade = \text{'A'}}(takes) return? Is σstu_id=’S4’(σgrade=’A’(takes))\sigma_{stu\_id = \text{'S4'}}(\sigma_{grade = \text{'A'}}(takes)) equal to σgrade=’A’∧stu_id=’S4’(takes)\sigma_{grade = \text{'A'} \land stu\_id = \text{'S4'}}(takes)?

Show answer
5 tuples; yes, both give (S4, MA101, A) and (S4, MA202, A)

The A grades: S1-CS101, S1-CS305, S3-EE210, S4-MA101, S4-MA202. A total of 5 rows.
Two selections in a row are always equal to a single ∧\land selection, and their order can be swapped (commutative). Both return the two A rows of S4.

Verification: All result tables were computed in verify/SEN2104/04.mjs with JS set operations (lib.mjs: sigma, pi, union, minus, intersect, product, rho), and the SQL equivalent of every expression was run on node:sqlite (SQLite 3.53) and checked to give the same result (54 checks, 0 errors).

Review card

σ_condition(R): selects ROWS, the number of columns stays the same. In the condition ∧ ∨ ¬ = ≠ < > π_list(R): selects COLUMNS, REMOVES DUPLICATES (like DISTINCT in SQL) R ∪ S, R − S, R ∩ S: must be union-compatible (same degree, same domains) R ∩ S = R − (R − S) (derived, not fundamental) R × S: rows |R|·|S|, columns degree(R)+degree(S); common names are R.a, S.a × + σ(equality) = join. Do not leave a product alone, it produces meaningless pairs ρ_x(R): name a copy; the only way to multiply a table by itself "both" → ∩ "or" → ∪ or σ(p ∨ q) "never did" → all − those who did Largest: all − (those that have a larger one), self-product with ρ σ_p(σ_q(R)) = σ_{p∧q}(R) π_a(π_ab(R)) = π_a(R) A comparison with NULL is not true, the row is dropped 6 fundamental: σ π ∪ − × ρ