Many-to-many relationship

Overview

Convert to two one-to-many relationships adding a junction table:

STUDENT           ENROLLMENT        COURSE
student_id  ―――→  student_id        title
name              course_id  ←――――  course_id
                  grade

Implementation in sqlite:

PRAGMA foreign_keys = ON;

CREATE TABLE student (
    student_id INTEGER PRIMARY KEY,
	name TEXT NOT NULL UNIQUE
);

CREATE TABLE course (
    course_id INTEGER PRIMARY KEY,
	title TEXT NOT NULL UNIQUE
);

CREATE TABLE enrollment (
    student_id INTEGER NOT NULL REFERENCES student(student_id),
    course_id INTEGER NOT NULL REFERENCES course(course_id),
    PRIMARY KEY (student_id, course_id)
);	

Add students and courses

INSERT INTO student(name) VALUES ('John');
INSERT INTO course(title) VALUES ('Biology');
INSERT INTO student(name) VALUES ('Paul'), ('Mary'), ('Peter');
INSERT INTO course(title) VALUES ('Math'), ('History');

Rename

UPDATE student SET name='John Smith' WHERE name='John';
UPDATE course SET name='Biology 1' WHERE title='Biology';

Remove

DELETE FROM student WHERE name='John Smith';
DELETE FROM course WHERE title='Biology 1';

Enroll a student to a course

INSERT INTO enrollment(student_id, course_id)
VALUES (
    (SELECT student_id FROM student WHERE name='John'),
    (SELECT course_id FROM course WHERE title='Biology')
);

Unenroll a student from a course

DELETE FROM enrollment WHERE
student_id=(SELECT student_id FROM student WHERE name='John') AND
course_id=(SELECT course_id FROM course WHERE title='Biology');

Unenroll a student from all courses

DELETE FROM enrollment WHERE
student_id=(SELECT student_id FROM student WHERE name='John');

Unenroll all students from a course

DELETE FROM enrollment WHERE
course_id=(SELECT course_id FROM course WHERE title='Biology');

Report

All enrolled courses and their enrolled students:

SELECT title, name FROM student
JOIN enrollment USING (student_id)
JOIN course USING (course_id);

Courses without students:

SELECT title FROM course
WHERE course_id NOT IN
(SELECT course_id FROM enrollment);

Students not enrolled in any courses:

SELECT name FROM student
WHERE student_id NOT IN
(SELECT student_id FROM enrollment);