Chapter 3 — Relational Query Languages
3.1 Relational Algebra Operators
| Operator | Symbol | What it does |
|---|
| Selection | σ | Filter rows satisfying a predicate |
| Projection | π | Keep only specified columns (removes duplicates) |
| Cartesian product | × | All tuple combinations from two relations |
| Natural join | ⋈ | Join on matching attribute names, merge duplicates |
| Theta join | ⋈θ | Join with an arbitrary predicate θ |
| Equijoin | ⋈ | Join on equality; both copies of join attribute kept |
| Union | ∪ | All tuples in either relation (both must be union-compatible) |
| Intersection | ∩ | Tuples in both relations |
| Difference | − | Tuples in first but not second |
| Rename | ρ | Rename relation or attributes |
| Assignment | ← | Assign intermediate result to a name |
σdept=′CS′∧gpa>3.5(Student) πname,gpa(σdept=′CS′(Student)) Student⋈Student.sid=Enrollment.sidEnrollment Optimization tip: always apply σ before π and before ×/⋈. This reduces the size of intermediate results.
3.2 SQL Reference Schema (used in all examples)
CREATE TABLE Student (
sid INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
dept VARCHAR(50),
gpa DECIMAL(3,2) CHECK (gpa BETWEEN 0 AND 4)
);
CREATE TABLE Course (
cid INT PRIMARY KEY,
title VARCHAR(100) NOT NULL,
credits INT,
dept VARCHAR(50)
);
CREATE TABLE Enrollment (
sid INT REFERENCES Student(sid) ON DELETE CASCADE,
cid INT REFERENCES Course(cid) ON DELETE CASCADE,
grade CHAR(2),
year INT,
PRIMARY KEY (sid, cid)
);
CREATE TABLE Instructor (
iid INT PRIMARY KEY,
name VARCHAR(100),
dept VARCHAR(50),
salary DECIMAL(10,2)
);
CREATE TABLE Teaches (
iid INT REFERENCES Instructor(iid),
cid INT REFERENCES Course(cid),
PRIMARY KEY (iid, cid)
);
3.3 SELECT Statement — Full Syntax
SELECT [DISTINCT] col_list | *
FROM table_list | join_expression
[WHERE row_predicate]
[GROUP BY group_columns]
[HAVING group_predicate]
[ORDER BY col [ASC|DESC]]
[LIMIT n]
Logical execution order (not written order):
FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT
-- Basic filter + sort
SELECT name, gpa
FROM Student
WHERE dept = 'CS' AND gpa > 3.5
ORDER BY gpa DESC;
-- DISTINCT — remove duplicates
SELECT DISTINCT dept FROM Student;
-- Aggregate functions
SELECT
dept,
COUNT(*) AS total,
AVG(gpa) AS avg_gpa,
MAX(gpa) AS top_gpa,
MIN(gpa) AS low_gpa,
SUM(credits) AS total_credits -- from Course
FROM Student
GROUP BY dept
HAVING AVG(gpa) > 3.0
ORDER BY avg_gpa DESC;
-- ── JOINS ────────────────────────────────────────────────────────────────────
-- INNER JOIN — only matching rows
SELECT s.name, c.title, e.grade
FROM Student s
JOIN Enrollment e ON s.sid = e.sid
JOIN Course c ON e.cid = c.cid
WHERE c.dept = 'CS';
-- LEFT OUTER JOIN — all students, even unenrolled
SELECT s.name, e.cid
FROM Student s
LEFT JOIN Enrollment e ON s.sid = e.sid;
-- RIGHT OUTER JOIN
SELECT s.name, c.title
FROM Enrollment e
RIGHT JOIN Course c ON e.cid = c.cid;
-- FULL OUTER JOIN
SELECT s.name, c.title
FROM Student s
FULL OUTER JOIN Enrollment e ON s.sid = e.sid
FULL OUTER JOIN Course c ON e.cid = c.cid;
-- CROSS JOIN (Cartesian product)
SELECT s.name, c.title
FROM Student s CROSS JOIN Course c;
-- NATURAL JOIN — auto-joins on same-named columns
SELECT * FROM Student NATURAL JOIN Enrollment;
-- Self join — students in the same department
SELECT a.name AS s1, b.name AS s2, a.dept
FROM Student a JOIN Student b ON a.dept = b.dept AND a.sid < b.sid;
-- ── SUBQUERIES ───────────────────────────────────────────────────────────────
-- Non-correlated — independent of outer query, runs once
SELECT name FROM Student
WHERE sid IN (SELECT sid FROM Enrollment WHERE grade = 'A');
-- Correlated — references outer row, runs once per outer row
SELECT name, gpa, dept
FROM Student s
WHERE gpa > (SELECT AVG(gpa) FROM Student s2 WHERE s2.dept = s.dept);
-- EXISTS / NOT EXISTS
SELECT name FROM Student s
WHERE EXISTS (
SELECT 1 FROM Enrollment e WHERE e.sid = s.sid AND e.grade = 'A'
);
-- Students who never enrolled in any course
SELECT name FROM Student s
WHERE NOT EXISTS (SELECT 1 FROM Enrollment e WHERE e.sid = s.sid);
-- Scalar subquery in SELECT
SELECT name, (SELECT COUNT(*) FROM Enrollment e WHERE e.sid = s.sid) AS course_count
FROM Student s;
-- ── SET OPERATIONS ───────────────────────────────────────────────────────────
-- UNION — students in CS or IT (no duplicates)
SELECT sid FROM Student WHERE dept = 'CS'
UNION
SELECT sid FROM Student WHERE dept = 'IT';
-- UNION ALL — keep duplicates
SELECT sid FROM Student WHERE dept = 'CS'
UNION ALL
SELECT sid FROM Student WHERE gpa > 3.8;
-- INTERSECT — enrolled in BOTH course 101 and 102
SELECT sid FROM Enrollment WHERE cid = 101
INTERSECT
SELECT sid FROM Enrollment WHERE cid = 102;
-- EXCEPT / MINUS — enrolled in 101 but NOT 102
SELECT sid FROM Enrollment WHERE cid = 101
EXCEPT
SELECT sid FROM Enrollment WHERE cid = 102;
-- ── DML: INSERT · UPDATE · DELETE ───────────────────────────────────────────
-- INSERT single row
INSERT INTO Student (sid, name, dept, gpa) VALUES (10, 'Ravi', 'CS', 3.7);
-- INSERT multiple rows
INSERT INTO Student VALUES
(11, 'Priya', 'IT', 3.5),
(12, 'Sita', 'CS', 3.9);
-- INSERT from SELECT
INSERT INTO CS_Backup SELECT * FROM Student WHERE dept = 'CS';
-- UPDATE — give all CS students a GPA boost (capped at 4.0)
UPDATE Student
SET gpa = LEAST(gpa + 0.1, 4.0)
WHERE dept = 'CS';
-- UPDATE with subquery
UPDATE Student
SET dept = 'CS'
WHERE sid IN (SELECT sid FROM Enrollment WHERE cid = 101);
-- DELETE rows
DELETE FROM Student WHERE gpa < 1.5;
-- DELETE with subquery — remove students not enrolled anywhere
DELETE FROM Student
WHERE sid NOT IN (SELECT DISTINCT sid FROM Enrollment);
-- ── VIEWS ────────────────────────────────────────────────────────────────────
-- Simple view
CREATE VIEW CS_Students AS
SELECT sid, name, gpa
FROM Student
WHERE dept = 'CS';
-- View with join
CREATE VIEW Student_Courses AS
SELECT s.name, c.title, e.grade
FROM Student s
JOIN Enrollment e ON s.sid = e.sid
JOIN Course c ON e.cid = c.cid;
-- WITH CHECK OPTION — prevents inserts/updates that violate the view's WHERE
CREATE VIEW High_GPA AS
SELECT * FROM Student WHERE gpa > 3.5
WITH CHECK OPTION;
-- Materialized view (stores the result physically — PostgreSQL)
CREATE MATERIALIZED VIEW Dept_Stats AS
SELECT dept, COUNT(*) AS cnt, AVG(gpa) AS avg_gpa
FROM Student
GROUP BY dept;
REFRESH MATERIALIZED VIEW Dept_Stats;
-- Drop view
DROP VIEW CS_Students;
-- ── TRIGGERS ─────────────────────────────────────────────────────────────────
-- PostgreSQL trigger: validate GPA before insert or update
CREATE OR REPLACE FUNCTION validate_gpa()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.gpa < 0 OR NEW.gpa > 4.0 THEN
RAISE EXCEPTION 'GPA must be between 0.0 and 4.0, got %', NEW.gpa;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_gpa_check
BEFORE INSERT OR UPDATE ON Student
FOR EACH ROW EXECUTE FUNCTION validate_gpa();
-- Audit trigger — log all deletions
CREATE TABLE Student_Audit (
deleted_at TIMESTAMP DEFAULT NOW(),
sid INT, name VARCHAR(100), dept VARCHAR(50)
);
CREATE OR REPLACE FUNCTION audit_student_delete()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO Student_Audit(sid, name, dept) VALUES (OLD.sid, OLD.name, OLD.dept);
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_student_audit
AFTER DELETE ON Student
FOR EACH ROW EXECUTE FUNCTION audit_student_delete();
-- ── STORED PROCEDURES ────────────────────────────────────────────────────────
CREATE OR REPLACE PROCEDURE enroll_student(
p_sid INT,
p_cid INT,
p_grade CHAR(2) DEFAULT 'IP'
)
LANGUAGE plpgsql AS $$
BEGIN
-- Check student exists
IF NOT EXISTS (SELECT 1 FROM Student WHERE sid = p_sid) THEN
RAISE EXCEPTION 'Student % not found', p_sid;
END IF;
-- Insert enrollment
INSERT INTO Enrollment(sid, cid, grade, year)
VALUES (p_sid, p_cid, p_grade, EXTRACT(YEAR FROM NOW())::INT)
ON CONFLICT (sid, cid) DO UPDATE SET grade = EXCLUDED.grade;
END;
$$;
CALL enroll_student(1, 101, 'A');
-- ── GRANT / REVOKE ────────────────────────────────────────────────────────────
CREATE ROLE student_role;
GRANT SELECT ON Student, Course, Enrollment TO student_role;
CREATE USER alice WITH PASSWORD 'pass123';
GRANT student_role TO alice;
GRANT INSERT, UPDATE ON Enrollment TO alice;
GRANT SELECT ON Student TO alice WITH GRANT OPTION; -- alice can further grant
REVOKE INSERT ON Enrollment FROM alice;
REVOKE student_role FROM alice;
Exam Quick-Reference
- Relational algebra evaluation order: σ first, π last, reduce intermediate sizes.
- SQL logical order: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.
- HAVING filters groups; WHERE filters rows (before grouping).
- Correlated subquery re-runs per outer row; non-correlated runs once.
- View = stored query; Materialized view = stored query result (refreshed).
- Trigger fires automatically on INSERT/UPDATE/DELETE; procedure is called explicitly.