initial commit
This commit is contained in:
17 files changed
+1277
No files matched your search
@@ -0,0 +1,48 @@
|
||||
-- 1.
|
||||
SELECT le_section_id, lab_set_code, course_code, la_title, lab_day_of_week
|
||||
FROM lab_event
|
||||
INNER JOIN lab_section
|
||||
ON lab_section.lab_section_id = lab_event.le_section_id
|
||||
INNER JOIN lab_assignment
|
||||
ON lab_assignment.la_lab_number = lab_event.le_number
|
||||
WHERE term_code = '202530';
|
||||
|
||||
-- 2.
|
||||
SELECT pgr_student_id, COUNT(*) AS labs_attended
|
||||
FROM progress
|
||||
GROUP BY pgr_student_id;
|
||||
|
||||
-- 3.
|
||||
SELECT pgr_student_id, student_set_code, lab_section_id, COUNT(*) FILTER (WHERE pgr_late 1= 'f') AS late_submissions
|
||||
FROM progress
|
||||
INNER JOIN student
|
||||
ON student.student_id = progress.pgr_student_id
|
||||
INNER JOIN lab_section
|
||||
ON student.student_set_code = lab_section.lab_set_code
|
||||
GROUP BY pgr_student_id, student_set_code, lab_section_id;
|
||||
|
||||
-- 4.
|
||||
SELECT student_set_code, TO_CHAR(AVG(pgr_instructor_assessment::numeric), 'FM999999.00') AS section_average
|
||||
FROM progress
|
||||
INNER JOIN student
|
||||
ON student.student_id = progress.pgr_student_id
|
||||
GROUP BY student_set_code
|
||||
ORDER BY student_set_code;
|
||||
|
||||
-- 5.
|
||||
SELECT student_first_name || ' ' || student_last_name AS student_name, student_set_code, le_number
|
||||
FROM student
|
||||
INNER JOIN progress
|
||||
ON progress.pgr_student_id = student.student_id
|
||||
INNER JOIN lab_event
|
||||
ON lab_event.le_id = progress.pgr_event_id
|
||||
WHERE pgr_instructor_assessment IS NULL OR pgr_self_assessment IS NULL;
|
||||
|
||||
-- 6.
|
||||
SELECT student_id, student_first_name || ' ' || student_last_name AS student_name, student_set_code, TO_CHAR(AVG(pgr_instructor_assessment::numeric), 'FM999999.00') AS student_average
|
||||
FROM student
|
||||
JOIN progress
|
||||
ON student.student_id = progress.pgr_student_id
|
||||
GROUP BY student_id, student_first_name, student_last_name, student_set_code
|
||||
HAVING AVG(pgr_instructor_assessment::numeric) >= 4.5
|
||||
ORDER BY student_id;
|
||||
@@ -0,0 +1,56 @@
|
||||
CREATE OR REPLACE VIEW ta_view AS
|
||||
SELECT
|
||||
ls.lab_section_id AS lab_section,
|
||||
e.le_id,
|
||||
s.student_id,
|
||||
s.student_first_name || ' ' ||
|
||||
s.student_last_name AS full_name,
|
||||
p.pgr_attendance,
|
||||
p.pgr_inlab_submission_link,
|
||||
p.pgr_instructor_assessment
|
||||
FROM progress p
|
||||
JOIN student s
|
||||
ON p.pgr_student_id = s.student_id
|
||||
JOIN lab_event e
|
||||
ON p.pgr_event_id = e.le_id
|
||||
JOIN lab_section ls
|
||||
ON e.le_section_id = ls.lab_section_id;
|
||||
|
||||
CREATE OR REPLACE VIEW v_section_overview AS
|
||||
SELECT
|
||||
t.term_code,
|
||||
ss.set_code AS set_name,
|
||||
c.course_code,
|
||||
ls.lab_section_id AS section_id,
|
||||
COUNT(DISTINCT le.le_id) AS total_events,
|
||||
AVG(CAST(p.pgr_instructor_assessment AS NUMERIC)) AS avg_instructor_assessment
|
||||
FROM lab_section AS ls
|
||||
JOIN course AS c ON c.course_code = ls.lab_course_code
|
||||
JOIN term AS t ON t.term_code = ls.lab_term_code
|
||||
JOIN student_set AS ss ON ss.set_code = ls.lab_set_code
|
||||
LEFT JOIN lab_event AS le
|
||||
ON le.le_section_id = ls.lab_section_id
|
||||
AND le.course_code = ls.lab_course_code
|
||||
AND le.term_code = ls.lab_term_code
|
||||
LEFT JOIN progress AS p
|
||||
ON p.pgr_event_id = le.le_id
|
||||
GROUP BY
|
||||
t.term_code,
|
||||
ss.set_code,
|
||||
c.course_code,
|
||||
ls.lab_section_id;
|
||||
|
||||
--everything from section
|
||||
SELECT *
|
||||
FROM v_section_overview
|
||||
ORDER BY term_code, set_name, course_code, section_id;
|
||||
|
||||
-- only sections that actually have events
|
||||
SELECT *
|
||||
FROM v_section_overview
|
||||
WHERE total_events > 0
|
||||
ORDER BY total_events DESC;
|
||||
|
||||
--This is the view for ta
|
||||
SELECT *
|
||||
FROM ta_view;
|
||||
@@ -0,0 +1,11 @@
|
||||
-- 1. Create a role for TAs
|
||||
CREATE ROLE ta_role;
|
||||
|
||||
-- 2. Allow this role to view your TA-related views
|
||||
GRANT SELECT ON v_ta_progress_summary, v_section_overview TO ta_role;
|
||||
|
||||
-- 3. Create a demo user (only works if your server allows user creation)
|
||||
CREATE USER ta_demo WITH PASSWORD 'ta_demo123';
|
||||
|
||||
-- 4. Give the demo user the TA role
|
||||
GRANT ta_role TO ta_demo;
|
||||
@@ -0,0 +1,44 @@
|
||||
Primary Keys
|
||||
For our design, we decided to go with natural primary keys for all tables because the data we were given in the CSVs already included unique identifiers that made sense in the real world.
|
||||
We didn’t see a reason to generate artificial IDs since each table had something that was already unique and meaningful.
|
||||
Natural PKs we used:
|
||||
course_code – e.g. COMP1510
|
||||
term_code – e.g. 202530
|
||||
student_set – e.g. SETD
|
||||
student – uses student_id (like A001)
|
||||
lab_section – uses lab_section_id (like L01)
|
||||
lab_assignment – uses la_assignment_id (like LAB01)
|
||||
lab_event – uses le_id (like L01-L01)
|
||||
user_account, progress, and progress_change_log also use text-based IDs that are unique.
|
||||
|
||||
Foreign Keys & Relationships
|
||||
We made sure every relationship matched the business rules:
|
||||
Students must belong to a Set, and the student_set_code can’t be null.
|
||||
If a set code changes, it cascades to all students (ON UPDATE CASCADE).
|
||||
Lab Sections link to a Course, Term, and Set. All of those are required and set to cascade on update too.
|
||||
Lab Events belong to a Lab Section, and we used a composite foreign key (le_section_id, course_code, term_code) to make sure the event always matches the correct section, course, and term. We also added ON DELETE CASCADE so deleting a section deletes its events automatically.
|
||||
Student_Section connects students to lab sections, and if a section gets deleted, the link goes with it.
|
||||
Progress connects a student to a lab event. Deleting an event now also deletes any related progress (we used ON DELETE CASCADE for that).
|
||||
Progress Change Log connects to both progress and user_account. Deleting a progress record removes its log, but deleting a user is blocked to protect the audit trail.
|
||||
|
||||
Uniqueness & Constraints
|
||||
Student emails must be unique (no duplicate addresses).
|
||||
Each combination of (lab_section_id, lab_course_code, lab_term_code) is unique to prevent mix-ups between sections.
|
||||
Term codes must follow the six-digit format (CHECK (term_code ~ '^[0-9]{6}$')).
|
||||
Course credits must be between 1 and 9.
|
||||
lab_event checks that le_ends_at is after le_starts_at.
|
||||
progress checks that pgr_polished_submitted_at is after pgr_inlab_submitted_at when both are present.
|
||||
Boolean fields like pgr_prepared and pgr_late default to FALSE.
|
||||
|
||||
Cascading Logic
|
||||
We used cascading only when it made logical sense:
|
||||
Deleting a lab_section removes its lab_events, which also removes any related progress and change logs automatically.
|
||||
For tables like user_account, we kept delete restricted so we don’t lose audit history.
|
||||
|
||||
Naming Conventions
|
||||
We used prefixes to make joins easier and keep things organized.
|
||||
For example:
|
||||
le_ for lab_event columns,
|
||||
pgr_ for progress,
|
||||
chl_ for progress_change_log.
|
||||
Also, every constraint is named properly (pk_, fk_, ck_, uq_) so if there’s an error, it’s obvious where it came from.
|
||||
@@ -0,0 +1,168 @@
|
||||
DROP SCHEMA IF EXISTS lab_tracker_group_22 CASCADE;
|
||||
CREATE SCHEMA lab_tracker_group_22;
|
||||
SET search_path TO lab_tracker_group_22;
|
||||
|
||||
DROP TABLE IF EXISTS progress_change_log;
|
||||
DROP TABLE IF EXISTS progress;
|
||||
DROP TABLE IF EXISTS lab_event;
|
||||
DROP TABLE IF EXISTS lab_assignment;
|
||||
DROP TABLE IF EXISTS student_section;
|
||||
DROP TABLE IF EXISTS lab_section;
|
||||
DROP TABLE IF EXISTS student;
|
||||
DROP TABLE IF EXISTS user_account;
|
||||
DROP TABLE IF EXISTS student_set;
|
||||
DROP TABLE IF EXISTS term;
|
||||
DROP TABLE IF EXISTS course;
|
||||
|
||||
CREATE TABLE course (
|
||||
course_code VARCHAR(20) CONSTRAINT pk_course PRIMARY KEY,
|
||||
course_title VARCHAR(200),
|
||||
credits NUMERIC(3,0)
|
||||
CONSTRAINT ck_course_credits CHECK (credits BETWEEN 1 AND 9)
|
||||
);
|
||||
|
||||
CREATE TABLE term (
|
||||
term_code VARCHAR(10) CONSTRAINT pk_term PRIMARY KEY,
|
||||
term_name VARCHAR(50),
|
||||
term_start_date DATE,
|
||||
term_end_date DATE,
|
||||
CONSTRAINT ck_term_code_fmt CHECK (term_code ~ '^[0-9]{6}$')
|
||||
);
|
||||
|
||||
CREATE TABLE student_set (
|
||||
set_code VARCHAR(10) CONSTRAINT pk_student_set PRIMARY KEY,
|
||||
set_campus VARCHAR(50)
|
||||
);
|
||||
|
||||
CREATE TABLE user_account (
|
||||
user_id VARCHAR(50) CONSTRAINT pk_user_account PRIMARY KEY,
|
||||
user_full_name VARCHAR(120) NOT NULL,
|
||||
user_role VARCHAR(30),
|
||||
user_email VARCHAR(120) CONSTRAINT uq_user_email UNIQUE
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE student (
|
||||
student_id VARCHAR(30) CONSTRAINT pk_student PRIMARY KEY,
|
||||
student_set_code VARCHAR(10) NOT NULL,
|
||||
student_first_name VARCHAR(80) NOT NULL,
|
||||
student_last_name VARCHAR(80) NOT NULL,
|
||||
student_email VARCHAR(120),
|
||||
CONSTRAINT uq_student_email UNIQUE (student_email),
|
||||
CONSTRAINT fk_student_set
|
||||
FOREIGN KEY (student_set_code)
|
||||
REFERENCES student_set(set_code)
|
||||
ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE lab_section (
|
||||
lab_section_id VARCHAR(20) CONSTRAINT pk_lab_section PRIMARY KEY,
|
||||
lab_course_code VARCHAR(20) NOT NULL,
|
||||
lab_term_code VARCHAR(10) NOT NULL,
|
||||
lab_set_code VARCHAR(10) NOT NULL,
|
||||
lab_section_type VARCHAR(10),
|
||||
lab_day_of_week VARCHAR(10),
|
||||
lab_start_time TIME,
|
||||
lab_end_time TIME,
|
||||
lab_location VARCHAR(100),
|
||||
|
||||
CONSTRAINT fk_lab_section_course FOREIGN KEY (lab_course_code)
|
||||
REFERENCES course(course_code) ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_lab_section_term FOREIGN KEY (lab_term_code)
|
||||
REFERENCES term(term_code) ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_lab_section_set FOREIGN KEY (lab_set_code)
|
||||
REFERENCES student_set(set_code) ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT uq_lab_section_triplet
|
||||
UNIQUE (lab_section_id, lab_course_code, lab_term_code)
|
||||
);
|
||||
|
||||
CREATE TABLE student_section (
|
||||
ss_section_id VARCHAR(20) NOT NULL,
|
||||
ss_student_id VARCHAR(30) NOT NULL,
|
||||
CONSTRAINT pk_student_section PRIMARY KEY (ss_section_id, ss_student_id),
|
||||
CONSTRAINT fk_student_section_section FOREIGN KEY (ss_section_id)
|
||||
REFERENCES lab_section(lab_section_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_student_section_student FOREIGN KEY (ss_student_id)
|
||||
REFERENCES student(student_id) ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE lab_assignment (
|
||||
la_assignment_id VARCHAR(20) CONSTRAINT pk_lab_assignment PRIMARY KEY, la_course_code VARCHAR(20) NOT NULL,
|
||||
la_term_code VARCHAR(10),
|
||||
la_lab_number INTEGER,
|
||||
la_title VARCHAR(200),
|
||||
CONSTRAINT fk_assignment_course FOREIGN KEY (la_course_code)
|
||||
REFERENCES course(course_code) ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_assignment_term FOREIGN KEY (la_term_code)
|
||||
REFERENCES term(term_code) ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE lab_event (
|
||||
le_id VARCHAR(32) CONSTRAINT pk_lab_event PRIMARY KEY,
|
||||
le_section_id VARCHAR(20) NOT NULL,
|
||||
course_code VARCHAR(20) NOT NULL,
|
||||
term_code VARCHAR(10) NOT NULL,
|
||||
le_number INTEGER NOT NULL,
|
||||
le_starts_at TIMESTAMP NOT NULL,
|
||||
le_ends_at TIMESTAMP NOT NULL,
|
||||
le_due_at TIMESTAMP,
|
||||
le_location VARCHAR(100),
|
||||
|
||||
CONSTRAINT fk_event_section_triplet
|
||||
FOREIGN KEY (le_section_id, course_code, term_code)
|
||||
REFERENCES lab_section (lab_section_id, lab_course_code, lab_term_code)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE,
|
||||
|
||||
CONSTRAINT ck_event_time_order CHECK (le_ends_at > le_starts_at)
|
||||
);
|
||||
|
||||
CREATE TABLE progress (
|
||||
pgr_id VARCHAR(50) CONSTRAINT pk_progress PRIMARY KEY,
|
||||
pgr_student_id VARCHAR(30) NOT NULL,
|
||||
pgr_event_id VARCHAR(32) NOT NULL,
|
||||
pgr_lab_number INTEGER,
|
||||
pgr_status VARCHAR(50),
|
||||
pgr_prepared BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
pgr_attendance VARCHAR(20),
|
||||
pgr_inlab_submitted_at TIMESTAMP,
|
||||
pgr_inlab_submission_link TEXT,
|
||||
pgr_polished_submitted_at TIMESTAMP,
|
||||
pgr_polished_submission_link TEXT,
|
||||
pgr_instructor_assessment TEXT,
|
||||
pgr_self_assessment TEXT,
|
||||
pgr_late BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
CONSTRAINT fk_prog_student
|
||||
FOREIGN KEY (pgr_student_id)
|
||||
REFERENCES student(student_id)
|
||||
ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT fk_prog_event
|
||||
FOREIGN KEY (pgr_event_id)
|
||||
REFERENCES lab_event(le_id)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE,
|
||||
|
||||
CONSTRAINT ck_prog_time_order CHECK (
|
||||
pgr_polished_submitted_at IS NULL
|
||||
OR pgr_inlab_submitted_at IS NULL
|
||||
OR pgr_polished_submitted_at >= pgr_inlab_submitted_at
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE progress_change_log (
|
||||
chl_change_id VARCHAR(20) CONSTRAINT pk_progress_change_log PRIMARY KEY,
|
||||
chl_progress_id VARCHAR(50) NOT NULL,
|
||||
chl_changed_by VARCHAR(50) NOT NULL,
|
||||
chl_changed_at TIMESTAMP NOT NULL,
|
||||
chl_field VARCHAR(100) NOT NULL,
|
||||
chl_old_value VARCHAR(255),
|
||||
chl_new_value VARCHAR(255),
|
||||
chl_reason TEXT,
|
||||
CONSTRAINT fk_chglog_progress FOREIGN KEY (chl_progress_id)
|
||||
REFERENCES progress(pgr_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_chglog_user FOREIGN KEY (chl_changed_by)
|
||||
REFERENCES user_account(user_id) ON UPDATE CASCADE
|
||||
);
|
||||
@@ -0,0 +1,186 @@
|
||||
-- Clean DB before inserting
|
||||
TRUNCATE TABLE progress_change_log CASCADE;
|
||||
TRUNCATE TABLE progress CASCADE;
|
||||
TRUNCATE TABLE lab_event CASCADE;
|
||||
TRUNCATE TABLE lab_assignment CASCADE;
|
||||
TRUNCATE TABLE student_section CASCADE;
|
||||
TRUNCATE TABLE lab_section CASCADE;
|
||||
TRUNCATE TABLE student CASCADE;
|
||||
TRUNCATE TABLE user_account CASCADE;
|
||||
TRUNCATE TABLE student_set CASCADE;
|
||||
TRUNCATE TABLE term CASCADE;
|
||||
TRUNCATE TABLE course CASCADE;
|
||||
|
||||
-- Insert courses
|
||||
INSERT INTO course
|
||||
(course_code, course_title, credits)
|
||||
VALUES
|
||||
('COMP2714', 'Relational Database Systems', 3);
|
||||
|
||||
-- Insert terms
|
||||
INSERT INTO term
|
||||
(term_code, term_name, term_start_date, term_end_date)
|
||||
VALUES
|
||||
('202510', 'Winter 2025', '2025-01-06', '2025-04-11'),
|
||||
('202520', 'Spring/Summer 2025', '2025-04-28', '2025-08-08'),
|
||||
('202530', 'Fall 2025', '2025-09-02', '2025-12-12');
|
||||
|
||||
-- Insert student sets
|
||||
INSERT INTO student_set
|
||||
(set_code, set_campus)
|
||||
VALUES
|
||||
('A', 'Burnaby'),
|
||||
('B', 'Burnaby'),
|
||||
('C', 'Burnaby'),
|
||||
('D', 'Burnaby'),
|
||||
('E', 'Downtown'),
|
||||
('F', 'Downtown');
|
||||
|
||||
-- Insert users
|
||||
INSERT INTO user_account
|
||||
(user_id, user_full_name, user_role, user_email)
|
||||
VALUES
|
||||
('u_instructor', 'Maryam Khezrzadeh', 'instructor', 'mkhezrzadeh@bcit.ca'),
|
||||
('u_ta1', 'Daniel Saavedra', 'ta', 'dsaavedra@bcit.ca'),
|
||||
('u_system', 'Lab Tracker System', 'system', 'noreply@labtracker.local');
|
||||
|
||||
-- Insert students
|
||||
INSERT INTO student
|
||||
(student_id, student_set_code, student_first_name, student_last_name, student_email)
|
||||
VALUES
|
||||
('A001', 'A', 'Ava', 'Nguyen', 'ava.nguyen@my.bcit.ca'),
|
||||
('A002', 'A', 'Noah', 'Kim', 'noah.kim@my.bcit.ca'),
|
||||
('A003', 'A', 'Oliver', 'Singh', 'oliver.singh@my.bcit.ca'),
|
||||
('B001', 'B', 'Maya', 'Fischer', 'maya.fischer@my.bcit.ca'),
|
||||
('B002', 'B', 'Leo', 'Park', 'leo.park@my.bcit.ca'),
|
||||
('B003', 'B', 'Zoé', 'Martin', 'zoe.martin@my.bcit.ca'),
|
||||
('C001', 'C', 'Sofia', 'Chen', 'sofia.chen@my.bcit.ca'),
|
||||
('C002', 'C', 'Arjun', 'Patel', 'arjun.patel@my.bcit.ca'),
|
||||
('C003', 'C', 'Liam', 'O’Reilly', 'liam.oreilly@my.bcit.ca'),
|
||||
('D001', 'D', 'Layla', 'Haddad', 'layla.haddad@my.bcit.ca'),
|
||||
('D002', 'D', 'Ethan', 'Wong', 'ethan.wong@my.bcit.ca'),
|
||||
('D003', 'D', 'Nora', 'Iverson', 'nora.iverson@my.bcit.ca'),
|
||||
('E001', 'E', 'Diego', 'Alvarez', 'diego.alvarez@my.bcit.ca'),
|
||||
('E002', 'E', 'Hana', 'Yamamoto', 'hana.yamamoto@my.bcit.ca'),
|
||||
('E003', 'E', 'Farah', 'Rahimi', 'farah.rahimi@my.bcit.ca'),
|
||||
('F001', 'F', 'Marco', 'Russo', 'marco.russo@my.bcit.ca'),
|
||||
('F002', 'F', 'Amir', 'Kazemi', 'amir.kazemi@my.bcit.ca'),
|
||||
('F003', 'F', 'Chloe', 'Dubois', 'chloe.dubois@my.bcit.ca');
|
||||
|
||||
-- Insert lab sections
|
||||
INSERT INTO lab_section
|
||||
(lab_section_id, lab_course_code, lab_term_code, lab_set_code, lab_section_type, lab_day_of_week, lab_start_time, lab_end_time, lab_location)
|
||||
VALUES
|
||||
('L01', 'COMP2714', '202530', 'A', 'LAB', 'Mon', '09:30', '11:20', 'BBY-SW01-3460'),
|
||||
('L02', 'COMP2714', '202530', 'B', 'LAB', 'Mon', '13:30', '15:20', 'BBY-SW01-3465'),
|
||||
('L03', 'COMP2714', '202530', 'C', 'LAB', 'Tue', '18:30', '20:20', 'BBY-SW03-2605'),
|
||||
('L04', 'COMP2714', '202530', 'D', 'LAB', 'Wed', '09:30', '11:20', 'BBY-SE12-101'),
|
||||
('L05', 'COMP2714', '202530', 'E', 'LAB', 'Wed', '13:30', '15:20', 'DTC-310'),
|
||||
('L06', 'COMP2714', '202530', 'F', 'LAB', 'Thu', '18:30', '20:20', 'DTC-318');
|
||||
|
||||
-- Insert lab assignments
|
||||
INSERT INTO lab_assignment
|
||||
(la_assignment_id, la_course_code, la_term_code, la_lab_number, la_title)
|
||||
VALUES
|
||||
('LAB01', 'COMP2714', '202530', 1, 'Environment Setup & Intro SQL'),
|
||||
('LAB02', 'COMP2714', '202530', 2, 'Conceptual → Logical Mapping'),
|
||||
('LAB03', 'COMP2714', '202530', 3, 'Logical ERD & Constraints'),
|
||||
('LAB04', 'COMP2714', '202530', 4, 'Normalization to 3NF'),
|
||||
('LAB05', 'COMP2714', '202530', 5, 'DDL Implementation'),
|
||||
('LAB06', 'COMP2714', '202530', 6, 'DML: INSERT/UPDATE/DELETE'),
|
||||
('LAB07', 'COMP2714', '202530', 7, 'SELECT & JOIN Practice'),
|
||||
('LAB08', 'COMP2714', '202530', 8, 'Views & Indexes');
|
||||
|
||||
-- Insert student enrollments by set → section
|
||||
INSERT INTO student_section (ss_section_id, ss_student_id) VALUES
|
||||
('L01', 'A001'),
|
||||
('L01', 'A002'),
|
||||
('L01', 'A003'),
|
||||
('L02', 'B001'),
|
||||
('L02', 'B002'),
|
||||
('L02', 'B003'),
|
||||
('L03', 'C001'),
|
||||
('L03', 'C002'),
|
||||
('L03', 'C003'),
|
||||
('L04', 'D001'),
|
||||
('L04', 'D002'),
|
||||
('L04', 'D003'),
|
||||
('L05', 'E001'),
|
||||
('L05', 'E002'),
|
||||
('L05', 'E003'),
|
||||
('L06', 'F001'),
|
||||
('L06', 'F002'),
|
||||
('L06', 'F003');
|
||||
|
||||
|
||||
-- Insert lab events
|
||||
INSERT INTO lab_event
|
||||
(le_id, le_section_id, course_code, term_code, le_number, le_starts_at, le_ends_at, le_due_at, le_location)
|
||||
VALUES
|
||||
('L01-L01', 'L01', 'COMP2714', '202530', 1, '2025-09-08 09:30', '2025-09-08 11:20', '2025-09-14 23:59', 'BBY-SW01-3460'),
|
||||
('L01-L02', 'L01', 'COMP2714', '202530', 2, '2025-09-15 09:30', '2025-09-15 11:20', '2025-09-21 23:59', 'BBY-SW01-3460'),
|
||||
('L01-L03', 'L01', 'COMP2714', '202530', 3, '2025-09-22 09:30', '2025-09-22 11:20', '2025-09-28 23:59', 'BBY-SW01-3460'),
|
||||
('L02-L01', 'L02', 'COMP2714', '202530', 1, '2025-09-08 13:30', '2025-09-08 15:20', '2025-09-14 23:59', 'BBY-SW01-3465'),
|
||||
('L02-L02', 'L02', 'COMP2714', '202530', 2, '2025-09-15 13:30', '2025-09-15 15:20', '2025-09-21 23:59', 'BBY-SW01-3465'),
|
||||
('L02-L03', 'L02', 'COMP2714', '202530', 3, '2025-09-22 13:30', '2025-09-22 15:20', '2025-09-28 23:59', 'BBY-SW01-3465'),
|
||||
('L03-L01', 'L03', 'COMP2714', '202530', 1, '2025-09-09 18:30', '2025-09-09 20:20', '2025-09-14 23:59', 'BBY-SW03-2605'),
|
||||
('L03-L02', 'L03', 'COMP2714', '202530', 2, '2025-09-16 18:30', '2025-09-16 20:20', '2025-09-21 23:59', 'BBY-SW03-2605'),
|
||||
('L03-L03', 'L03', 'COMP2714', '202530', 3, '2025-09-23 18:30', '2025-09-23 20:20', '2025-09-28 23:59', 'BBY-SW03-2605'),
|
||||
('L04-L01', 'L04', 'COMP2714', '202530', 1, '2025-09-10 09:30', '2025-09-10 11:20', '2025-09-14 23:59', 'BBY-SE12-101'),
|
||||
('L04-L02', 'L04', 'COMP2714', '202530', 2, '2025-09-17 09:30', '2025-09-17 11:20', '2025-09-21 23:59', 'BBY-SE12-101'),
|
||||
('L04-L03', 'L04', 'COMP2714', '202530', 3, '2025-09-24 09:30', '2025-09-24 11:20', '2025-09-28 23:59', 'BBY-SE12-101'),
|
||||
('L05-L01', 'L05', 'COMP2714', '202530', 1, '2025-09-10 13:30', '2025-09-10 15:20', '2025-09-15 09:00', 'DTC-310'),
|
||||
('L05-L02', 'L05', 'COMP2714', '202530', 2, '2025-09-17 13:30', '2025-09-17 15:20', '2025-09-22 09:00', 'DTC-310'),
|
||||
('L05-L03', 'L05', 'COMP2714', '202530', 3, '2025-09-24 13:30', '2025-09-24 15:20', '2025-09-29 09:00', 'DTC-310'),
|
||||
('L06-L01', 'L06', 'COMP2714', '202530', 1, '2025-09-11 18:30', '2025-09-11 20:20', '2025-09-15 09:00', 'DTC-318'),
|
||||
('L06-L02', 'L06', 'COMP2714', '202530', 2, '2025-09-18 18:30', '2025-09-18 20:20', '2025-09-22 09:00', 'DTC-318'),
|
||||
('L06-L03', 'L06', 'COMP2714', '202530', 3, '2025-09-25 18:30', '2025-09-25 20:20', '2025-09-29 09:00', 'DTC-318');
|
||||
|
||||
-- Insert progress
|
||||
INSERT INTO progress
|
||||
(pgr_id, pgr_student_id, pgr_event_id, pgr_lab_number, pgr_status, pgr_prepared, pgr_attendance, pgr_inlab_submitted_at, pgr_inlab_submission_link, pgr_polished_submitted_at, pgr_polished_submission_link, pgr_instructor_assessment, pgr_self_assessment, pgr_late)
|
||||
VALUES
|
||||
('A001-L01-L01','A001', 'L01-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-08 10:45', 'https://submit.bcit.ca/comp2714/inlab/A001-L01-L01.pdf', '2025-09-09 12:45', 'https://submit.bcit.ca/comp2714/polished/A001-L01-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('A001-L01-L02','A001', 'L01-L02',2, 'Submitted', 'TRUE', 'Present', '2025-09-15 10:35', 'https://submit.bcit.ca/comp2714/inlab/A001-L01-L02.pdf', '2025-09-17 11:35', 'https://submit.bcit.ca/comp2714/polished/A001-L01-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('A002-L01-L01','A002', 'L01-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-08 10:45', 'https://submit.bcit.ca/comp2714/inlab/A002-L01-L01.pdf', '2025-09-09 12:45', 'https://submit.bcit.ca/comp2714/polished/A002-L01-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('A002-L01-L02','A002', 'L01-L02',2, 'In Progress', 'TRUE', 'Present', '2025-09-15 10:45', 'https://submit.bcit.ca/comp2714/inlab/A002-L01-L02.pdf', NULL, NULL, NULL, NULL, 'FALSE'),
|
||||
('A003-L01-L01','A003', 'L01-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-08 10:45', 'https://submit.bcit.ca/comp2714/inlab/A003-L01-L01.pdf', '2025-09-09 12:45', 'https://submit.bcit.ca/comp2714/polished/A003-L01-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('A003-L01-L02','A003', 'L01-L02',2, 'Submitted', 'FALSE', 'Present', '2025-09-15 10:35', 'https://submit.bcit.ca/comp2714/inlab/A003-L01-L02.pdf', '2025-09-17 11:35', 'https://submit.bcit.ca/comp2714/polished/A003-L01-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('B001-L02-L01','B001', 'L02-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-08 14:45', 'https://submit.bcit.ca/comp2714/inlab/B001-L02-L01.pdf', '2025-09-09 16:45', 'https://submit.bcit.ca/comp2714/polished/B001-L02-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('B001-L02-L02','B001', 'L02-L02',2, 'Submitted', 'TRUE', 'Present', '2025-09-15 14:35', 'https://submit.bcit.ca/comp2714/inlab/B001-L02-L02.pdf', '2025-09-17 15:35', 'https://submit.bcit.ca/comp2714/polished/B001-L02-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('B002-L02-L01','A002', 'L02-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-08 14:45', 'https://submit.bcit.ca/comp2714/inlab/B002-L02-L01.pdf', '2025-09-09 16:45', 'https://submit.bcit.ca/comp2714/polished/B002-L02-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('B002-L02-L02','A002', 'L02-L02',2, 'In Progress', 'TRUE', 'Present', '2025-09-15 14:40', 'https://submit.bcit.ca/comp2714/inlab/B002-L02-L02.pdf', NULL, NULL, NULL, NULL, 'FALSE'),
|
||||
('B003-L02-L01','B003', 'L02-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-08 14:45', 'https://submit.bcit.ca/comp2714/inlab/B003-L02-L01.pdf', '2025-09-09 16:45', 'https://submit.bcit.ca/comp2714/polished/B003-L02-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('B003-L02-L02','B003', 'L02-L02',2, 'Submitted', 'TRUE', 'Present', '2025-09-15 14:35', 'https://submit.bcit.ca/comp2714/inlab/B003-L02-L02.pdf', '2025-09-17 15:35', 'https://submit.bcit.ca/comp2714/polished/B003-L02-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('C001-L01-L01','C001', 'L03-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-09 19:45', 'https://submit.bcit.ca/comp2714/inlab/C001-L03-L01.pdf', '2025-09-10 21:45', 'https://submit.bcit.ca/comp2714/polished/C001-L03-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('C001-L01-L02','C001', 'L03-L02',2, 'Submitted', 'TRUE', 'Present', '2025-09-16 19:35', 'https://submit.bcit.ca/comp2714/inlab/C001-L03-L02.pdf', '2025-09-18 20:35', 'https://submit.bcit.ca/comp2714/polished/C001-L03-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('C002-L03-L01','C002', 'L03-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-09 19:45', 'https://submit.bcit.ca/comp2714/inlab/C002-L03-L01.pdf', '2025-09-10 21:45', 'https://submit.bcit.ca/comp2714/polished/C002-L03-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('C002-L03-L02','C002', 'L03-L02',2, 'In Progress', 'TRUE', 'Present', '2025-09-16 19:40', 'https://submit.bcit.ca/comp2714/inlab/C002-L03-L02.pdf', NULL, NULL, NULL, NULL, 'FALSE'),
|
||||
('C003-L03-L01','C003', 'L03-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-09 19:45', 'https://submit.bcit.ca/comp2714/inlab/C003-L03-L01.pdf', '2025-09-10 21:45', 'https://submit.bcit.ca/comp2714/polished/C003-L02-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('C003-L03-L02','C003', 'L03-L02',2, 'Submitted', 'FALSE', 'Present', '2025-09-16 19:35', 'https://submit.bcit.ca/comp2714/inlab/C003-L03-L02.pdf', '2025-09-18 20:35', 'https://submit.bcit.ca/comp2714/polished/C003-L02-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('D001-L04-L01','D001', 'L04-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-10 10:45', 'https://submit.bcit.ca/comp2714/inlab/D001-L04-L01.pdf', '2025-09-11 12:45', 'https://submit.bcit.ca/comp2714/polished/D001-L04-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('D001-L04-L02','D001', 'L04-L02',2, 'Submitted', 'TRUE', 'Present', '2025-09-17 10:35', 'https://submit.bcit.ca/comp2714/inlab/D001-L04-L02.pdf', '2025-09-19 11:35', 'https://submit.bcit.ca/comp2714/polished/D001-L04-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('D002-L04-L01','D002', 'L04-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-10 10:45', 'https://submit.bcit.ca/comp2714/inlab/D002-L04-L01.pdf', '2025-09-11 12:45', 'https://submit.bcit.ca/comp2714/polished/D002-L04-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('D002-L04-L02','D002', 'L04-L02',2, 'In Progress', 'TRUE', 'Present', '2025-09-17 10:40', 'https://submit.bcit.ca/comp2714/inlab/D002-L04-L02.pdf', NULL, NULL, NULL, NULL, 'FALSE'),
|
||||
('D003-L04-L01','D003', 'L04-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-10 10:45', 'https://submit.bcit.ca/comp2714/inlab/D003-L04-L01.pdf', '2025-09-11 12:45', 'https://submit.bcit.ca/comp2714/polished/D003-L04-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('D003-L04-L02','D003', 'L04-L02',2, 'Submitted', 'FALSE', 'Present', '2025-09-17 10:35', 'https://submit.bcit.ca/comp2714/inlab/D003-L04-L02.pdf', '2025-09-19 11:35', 'https://submit.bcit.ca/comp2714/polished/D003-L04-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('E001-L05-L01','E001', 'L05-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-10 14:45', 'https://submit.bcit.ca/comp2714/inlab/E001-L05-L01.pdf', '2025-09-11 16:45', 'https://submit.bcit.ca/comp2714/polished/E001-L05-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('E001-L05-L02','E001', 'L05-L02',2, 'Submitted', 'TRUE', 'Present', '2025-09-17 14:35', 'https://submit.bcit.ca/comp2714/inlab/E001-L05-L02.pdf', '2025-09-19 15:35', 'https://submit.bcit.ca/comp2714/polished/E001-L05-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('E002-L05-L01','E002', 'L05-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-10 14:45', 'https://submit.bcit.ca/comp2714/inlab/E002-L05-L01.pdf', '2025-09-11 16:45', 'https://submit.bcit.ca/comp2714/polished/E002-L05-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('E002-L05-L02','E002', 'L05-L02',2, 'In Progress', 'TRUE', 'Present', '2025-09-17 14:40', 'https://submit.bcit.ca/comp2714/inlab/E002-L05-L02.pdf', NULL, NULL, NULL, NULL, 'FALSE'),
|
||||
('E003-L05-L01','E003', 'L05-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-10 14:45', 'https://submit.bcit.ca/comp2714/inlab/E003-L05-L01.pdf', '2025-09-11 16:45', 'https://submit.bcit.ca/comp2714/polished/E003-L05-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('E003-L05-L02','E003', 'L05-L02',2, 'Submitted', 'FALSE', 'Present', '2025-09-17 14:35', 'https://submit.bcit.ca/comp2714/inlab/E003-L05-L02.pdf', '2025-09-19 15:35', 'https://submit.bcit.ca/comp2714/polished/E003-L05-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('F001-L06-L01','F001', 'L06-L01',2, 'Submitted', 'TRUE', 'Present', '2025-09-11 19:45', 'https://submit.bcit.ca/comp2714/inlab/F001-L06-L02.pdf', '2025-09-12 21:45', 'https://submit.bcit.ca/comp2714/polished/F001-L06-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('F001-L06-L02','F001', 'L06-L02',2, 'Submitted', 'TRUE', 'Present', '2025-09-18 19:35', 'https://submit.bcit.ca/comp2714/inlab/F001-L06-L02.pdf', '2025-09-20 20:35', 'https://submit.bcit.ca/comp2714/polished/F001-L06-L02.pdf', '7.0', '6.7', 'FALSE'),
|
||||
('F002-L06-L01','F002', 'L06-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-11 19:45', 'https://submit.bcit.ca/comp2714/inlab/F002-L06-L01.pdf', '2025-09-12 21:45', 'https://submit.bcit.ca/comp2714/polished/F002-L06-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('F002-L06-L02','F002', 'L06-L02',2, 'In Progress', 'TRUE', 'Present', '2025-09-18 19:40', 'https://submit.bcit.ca/comp2714/inlab/F002-L06-L02.pdf', NULL, NULL, NULL, NULL, 'FALSE'),
|
||||
('F003-L06-L01','F003', 'L06-L01',1, 'Submitted', 'TRUE', 'Present', '2025-09-11 19:45', 'https://submit.bcit.ca/comp2714/inlab/F003-L06-L01.pdf', '2025-09-12 21:45', 'https://submit.bcit.ca/comp2714/polished/F003-L06-L01.pdf', '8.5', '8.2', 'FALSE'),
|
||||
('F003-L06-L02','F003', 'L06-L02',2, 'Submitted', 'FALSE', 'Present', '2025-09-18 19:35', 'https://submit.bcit.ca/comp2714/inlab/F003-L06-L02.pdf', '2025-09-20 20:35', 'https://submit.bcit.ca/comp2714/polished/F003-L06-L02.pdf', '7.0', '6.7', 'FALSE');
|
||||
|
||||
-- Insert progress change logs
|
||||
INSERT INTO progress_change_log
|
||||
(chl_change_id, chl_progress_id, chl_changed_by, chl_changed_at, chl_field, chl_old_value, chl_new_value, chl_reason)
|
||||
VALUES
|
||||
('chg1', 'A001-L01-L01', 'u_instructor', '2025-09-09 12:10', 'instructor_assessment', '8.0', '8.5', 'Regraded after resubmission'),
|
||||
('chg2', 'A003-L01-L02', 'u_ta1', '2025-09-16 20:45', 'status', 'In Progress', 'Submitted', 'Student submitted during lab; TA marked as submitted'),
|
||||
('chg3', 'B003-L02-L01', 'u_system', '2025-09-23 23:59', 'late', 'False', 'True', 'Auto-flagged after set-specific due time');
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
-- Show all students with their section info Should work
|
||||
SELECT s.student_first_name, s.student_last_name, ls.lab_course_code, c.course_title, t.term_name
|
||||
FROM student s
|
||||
JOIN student_section ss ON s.student_id = ss.ss_student_id
|
||||
JOIN lab_section ls ON ss.ss_section_id = ls.lab_section_id
|
||||
JOIN course c ON ls.lab_course_code = c.course_code
|
||||
JOIN term t ON ls.lab_term_code = t.term_code;
|
||||
|
||||
-- Count students per lab section Should work
|
||||
SELECT ls.lab_course_code, COUNT(ss.ss_student_id) AS total_students
|
||||
FROM lab_section ls
|
||||
LEFT JOIN student_section ss ON ls.lab_section_id = ss.ss_section_id
|
||||
GROUP BY ls.lab_course_code;
|
||||
|
||||
-- View audit log Should work as intended
|
||||
SELECT pcl.chl_change_id, ua.user_full_name AS actor, pcl.chl_reason, pcl.chl_changed_at
|
||||
FROM progress_change_log pcl
|
||||
JOIN user_account ua ON pcl.chl_changed_by = ua.user_id;
|
||||
|
||||
-- returns students names and sets
|
||||
SELECT student_first_name, student_last_name, student_set_code
|
||||
FROM student ORDER BY student_set_code ASC;
|
||||
|
||||
-- This should fail and not work
|
||||
INSERT INTO course (course_code, course_title, credits)
|
||||
VALUES ('COMP9999', 'Invalid Credits', 0);
|
||||
|
||||
-- Delete a lab section -> should also delete lab_event
|
||||
-- and progress automatically cause of cascade
|
||||
DELETE FROM lab_section WHERE lab_section_id = 'L01';
|
||||
|
||||
-- Check remaining events and progress
|
||||
-- all should be empty due to cascade
|
||||
SELECT * FROM lab_event WHERE lab_event.le_section_id = 'L01';
|
||||
|
||||
SELECT * FROM progress JOIN lab_event ON progress.pgr_event_id = lab_event.le_id
|
||||
WHERE lab_event.le_section_id = 'L01';
|
||||
|
||||
SELECT * FROM progress_change_log JOIN progress ON progress_change_log.chl_progress_id = progress.pgr_id
|
||||
JOIN lab_event ON progress.pgr_event_id = lab_event.le_id
|
||||
WHERE lab_event.le_section_id = 'L01';
|
||||
Binary file not shown.
@@ -0,0 +1,147 @@
|
||||
SET search_path TO lab5;
|
||||
|
||||
-- TASK 1 – Enforce Section Capacity
|
||||
|
||||
-- 1. Trigger function: ensure no course offering exceeds capacity
|
||||
CREATE OR REPLACE FUNCTION check_offering_capacity()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
v_capacity INTEGER;
|
||||
v_current INTEGER;
|
||||
BEGIN
|
||||
SELECT off_capacity
|
||||
INTO v_capacity
|
||||
FROM course_offering
|
||||
WHERE off_id = NEW.off_id;
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO v_current
|
||||
FROM enrollment
|
||||
WHERE off_id = NEW.off_id
|
||||
AND enr_status = 'Active';
|
||||
|
||||
IF v_current >= v_capacity THEN
|
||||
RAISE EXCEPTION
|
||||
'Cannot enroll student %. Section % is full (capacity=%).',
|
||||
NEW.stu_num, NEW.off_id, v_capacity;
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
|
||||
-- 2. Trigger
|
||||
CREATE OR REPLACE TRIGGER trg_check_capacity
|
||||
BEFORE INSERT ON enrollment
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION check_offering_capacity();
|
||||
|
||||
-- TASK 2 – Enrollment Audit Logging
|
||||
|
||||
CREATE TABLE IF NOT EXISTS enrollment_audit (
|
||||
audit_id SERIAL PRIMARY KEY,
|
||||
enr_id_stu VARCHAR(20),
|
||||
enr_id_off INTEGER,
|
||||
action_type VARCHAR(10),
|
||||
old_status VARCHAR(8),
|
||||
new_status VARCHAR(8),
|
||||
action_ts TIMESTAMP DEFAULT NOW(),
|
||||
action_user TEXT DEFAULT current_user
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION audit_enrollment_changes()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
INSERT INTO enrollment_audit(
|
||||
enr_id_stu,
|
||||
enr_id_off,
|
||||
action_type,
|
||||
new_status
|
||||
)
|
||||
VALUES (
|
||||
NEW.stu_num,
|
||||
NEW.off_id,
|
||||
'INSERT',
|
||||
NEW.enr_status
|
||||
);
|
||||
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
INSERT INTO enrollment_audit(
|
||||
enr_id_stu,
|
||||
enr_id_off,
|
||||
action_type,
|
||||
old_status,
|
||||
new_status
|
||||
)
|
||||
VALUES (
|
||||
NEW.stu_num,
|
||||
NEW.off_id,
|
||||
'UPDATE',
|
||||
OLD.enr_status,
|
||||
NEW.enr_status
|
||||
);
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE TRIGGER trg_enrollment_audit
|
||||
AFTER INSERT OR UPDATE ON enrollment
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION audit_enrollment_changes();
|
||||
|
||||
-- TASK 3 – Validate Enrollment Status
|
||||
|
||||
ALTER TABLE enrollment DROP CONSTRAINT IF EXISTS enr_status_ck;
|
||||
|
||||
ALTER TABLE enrollment
|
||||
ADD CONSTRAINT enr_status_ck
|
||||
CHECK (enr_status IN ('Active', 'Dropped', 'Completed', 'Failed'));
|
||||
|
||||
CREATE OR REPLACE FUNCTION validate_enrollment_status()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF NEW.enr_status NOT IN ('Active','Dropped','Completed','Failed') THEN
|
||||
RAISE EXCEPTION 'Invalid enrollment status: %', NEW.enr_status;
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE TRIGGER trg_validate_status
|
||||
BEFORE INSERT OR UPDATE OF enr_status ON enrollment
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION validate_enrollment_status();
|
||||
|
||||
-- TESTS
|
||||
|
||||
INSERT INTO enrollment VALUES ('S100', 1, 'Active');
|
||||
INSERT INTO enrollment VALUES ('S101', 1, 'Active');
|
||||
INSERT INTO enrollment VALUES ('S102', 1, 'Active');
|
||||
|
||||
INSERT INTO enrollment VALUES ('S200', 2, 'Active');
|
||||
UPDATE enrollment SET enr_status = 'Dropped'
|
||||
WHERE stu_num = 'S200' AND off_id = 2;
|
||||
|
||||
UPDATE enrollment
|
||||
SET enr_status = 'Potato'
|
||||
WHERE stu_num = 'S200' AND off_id = 2;
|
||||
|
||||
-- OUTPUT
|
||||
|
||||
-- SELECT * FROM enrollment;
|
||||
|
||||
|
||||
-- SELECT * FROM enrollment_audit;
|
||||
|
||||
|
||||
-- REFLECTION
|
||||
-- Storing business rules directly inside the database ensures that
|
||||
-- data remains correct and consistent no matter what application
|
||||
-- or user interacts with it. Trigger-based validation centralizes
|
||||
-- logic so errors are prevented at the source instead of being caught
|
||||
-- later in the application.
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
-- 1. Create a schema for this lab (only runs once)
|
||||
CREATE SCHEMA IF NOT EXISTS lab5;
|
||||
|
||||
-- 2. Tell PostgreSQL to use this schema by default
|
||||
SET search_path TO lab5;
|
||||
|
||||
-- 3. Safety header: drop old tables if they exist
|
||||
DROP TABLE IF EXISTS location CASCADE;
|
||||
DROP TABLE IF EXISTS department CASCADE;
|
||||
DROP TABLE IF EXISTS professor CASCADE;
|
||||
DROP TABLE IF EXISTS student CASCADE;
|
||||
DROP TABLE IF EXISTS term CASCADE;
|
||||
DROP TABLE IF EXISTS course CASCADE;
|
||||
DROP TABLE IF EXISTS course_offering CASCADE;
|
||||
DROP TABLE IF EXISTS enrollment CASCADE;
|
||||
|
||||
-- 4. Create tables for lab5
|
||||
CREATE TABLE location (
|
||||
loc_building VARCHAR(10) NOT NULL,
|
||||
loc_room VARCHAR(10) NOT NULL,
|
||||
loc_code VARCHAR(20) GENERATED ALWAYS AS (
|
||||
loc_building || ' ' || loc_room
|
||||
) STORED PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE department (
|
||||
dep_code VARCHAR(10) PRIMARY KEY,
|
||||
dep_name VARCHAR(50) NOT NULL,
|
||||
dep_school VARCHAR(50) NOT NULL,
|
||||
dep_phone VARCHAR(12) NOT NULL,
|
||||
dep_email VARCHAR(50) NOT NULL,
|
||||
dep_website VARCHAR(50) NOT NULL,
|
||||
loc_code VARCHAR(10) REFERENCES location(loc_code)
|
||||
);
|
||||
|
||||
CREATE TABLE professor (
|
||||
prof_num VARCHAR(20) PRIMARY KEY,
|
||||
prof_fname VARCHAR(20) NOT NULL,
|
||||
prof_lname VARCHAR(20) NOT NULL,
|
||||
prof_email VARCHAR(50) NOT NULL,
|
||||
prof_phone VARCHAR(12) NOT NULL,
|
||||
prof_hired DATE NOT NULL,
|
||||
prof_office VARCHAR(20) REFERENCES location(loc_code) NOT NULL,
|
||||
dep_code VARCHAR(50) REFERENCES department(dep_code) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE term (
|
||||
term_year INTEGER NOT NULL,
|
||||
term_semester VARCHAR(10) NOT NULL,
|
||||
term_name VARCHAR(30) GENERATED ALWAYS AS (
|
||||
term_semester || ' ' || (term_year::text)
|
||||
) STORED,
|
||||
|
||||
term_code VARCHAR(6) GENERATED ALWAYS AS (
|
||||
(term_year::text) ||
|
||||
CASE term_semester
|
||||
WHEN 'Winter' THEN '10'
|
||||
WHEN 'Spring' THEN '30'
|
||||
WHEN 'Summer' THEN '40'
|
||||
WHEN 'Fall' THEN '50'
|
||||
END
|
||||
) STORED,
|
||||
|
||||
CONSTRAINT term_pk PRIMARY KEY (term_code),
|
||||
CONSTRAINT term_semester_ck CHECK (term_semester IN ('Winter','Spring','Summer','Fall'))
|
||||
);
|
||||
|
||||
CREATE TABLE student (
|
||||
stu_num VARCHAR(20) PRIMARY KEY,
|
||||
stu_fname VARCHAR(20) NOT NULL,
|
||||
stu_lname VARCHAR(20) NOT NULL,
|
||||
stu_email VARCHAR(50) NOT NULL,
|
||||
stu_phone VARCHAR(12) NOT NULL,
|
||||
stu_program VARCHAR(5) NOT NULL,
|
||||
stu_term VARCHAR(6) REFERENCES term(term_code) NOT NULL,
|
||||
stu_dept VARCHAR(10) REFERENCES department(dep_code) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE course (
|
||||
crs_subject VARCHAR(10) REFERENCES department(dep_code) NOT NULL,
|
||||
crs_num INTEGER NOT NULL,
|
||||
crs_title VARCHAR(50) NOT NULL,
|
||||
crd_credits NUMERIC(3,1) NOT NULL,
|
||||
dep_code VARCHAR(10) REFERENCES department(dep_code) NOT NULL,
|
||||
crs_desc TEXT NOT NULL,
|
||||
|
||||
crs_code VARCHAR(60) GENERATED ALWAYS AS (
|
||||
dep_code || ' ' || crs_num::text
|
||||
) STORED PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE course_offering (
|
||||
off_id SERIAL PRIMARY KEY,
|
||||
off_crs_code VARCHAR(60) REFERENCES course(crs_code) NOT NULL,
|
||||
off_term_code VARCHAR(6) REFERENCES term(term_code) NOT NULL,
|
||||
off_section VARCHAR(50) NOT NULL,
|
||||
off_type VARCHAR(10) NOT NULL,
|
||||
off_prof VARCHAR(20) REFERENCES professor(prof_num) NOT NULL,
|
||||
off_days VARCHAR(100) NOT NULL,
|
||||
off_start_time TIME NOT NULL,
|
||||
off_end_time TIME NOT NULL,
|
||||
off_loc VARCHAR(20) REFERENCES location(loc_code) NOT NULL,
|
||||
off_capacity INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT off_type_ck CHECK (off_type IN ('Lecture','Lab'))
|
||||
);
|
||||
|
||||
CREATE TABLE enrollment (
|
||||
stu_num VARCHAR(20) REFERENCES student(stu_num) NOT NULL,
|
||||
off_id INTEGER REFERENCES course_offering(off_id) NOT NULL,
|
||||
enr_status VARCHAR(8) NOT NULL,
|
||||
enr_final_grade VARCHAR(2),
|
||||
|
||||
CONSTRAINT enr_pk PRIMARY KEY (stu_num, off_id),
|
||||
CONSTRAINT enr_status_ck CHECK (enr_status IN ('Active', 'Dropped'))
|
||||
);
|
||||
+328
@@ -0,0 +1,328 @@
|
||||
TRUNCATE TABLE enrollment CASCADE;
|
||||
TRUNCATE TABLE course_offering CASCADE;
|
||||
TRUNCATE TABLE course CASCADE;
|
||||
TRUNCATE TABLE term CASCADE;
|
||||
TRUNCATE TABLE student CASCADE;
|
||||
TRUNCATE TABLE professor CASCADE;
|
||||
TRUNCATE TABLE department CASCADE;
|
||||
TRUNCATE TABLE location CASCADE;
|
||||
|
||||
-- TASK 1
|
||||
|
||||
INSERT INTO location VALUES (
|
||||
'SE12',
|
||||
'240'
|
||||
);
|
||||
|
||||
INSERT INTO location VALUES (
|
||||
'SE12',
|
||||
'260'
|
||||
);
|
||||
|
||||
INSERT INTO location VALUES (
|
||||
'SW01',
|
||||
'1015'
|
||||
);
|
||||
|
||||
INSERT INTO department VALUES (
|
||||
'COMP',
|
||||
'Computing',
|
||||
'Business & Media',
|
||||
'604-111-1111',
|
||||
'comp@bcit.ca',
|
||||
'https://bcit.ca/comp',
|
||||
'SE12 240'
|
||||
);
|
||||
|
||||
INSERT INTO department VALUES (
|
||||
'MATH',
|
||||
'Mathematics',
|
||||
'Applied Sciences',
|
||||
'604-222-2222',
|
||||
'math@bcit.ca',
|
||||
'https://bcit.ca/math',
|
||||
'SE12 260'
|
||||
);
|
||||
|
||||
INSERT INTO term VALUES (
|
||||
2025,
|
||||
'Fall'
|
||||
);
|
||||
|
||||
INSERT INTO term VALUES (
|
||||
2026,
|
||||
'Winter'
|
||||
);
|
||||
|
||||
INSERT INTO professor VALUES (
|
||||
'A00123456',
|
||||
'Ada',
|
||||
'Nguyen',
|
||||
'ada.nguyen@bcit.ca',
|
||||
'604-300-1111',
|
||||
'2019-08-15',
|
||||
'SE12 240',
|
||||
'COMP'
|
||||
);
|
||||
|
||||
INSERT INTO professor VALUES (
|
||||
'A00987654',
|
||||
'Raj',
|
||||
'Singh',
|
||||
'raj.singh@bcit.ca',
|
||||
'604-300-2222',
|
||||
'2015-09-01',
|
||||
'SE12 260',
|
||||
'COMP'
|
||||
);
|
||||
|
||||
INSERT INTO professor VALUES (
|
||||
'A00777777',
|
||||
'Maria',
|
||||
'Lopez',
|
||||
'maria.lopez@bcit.ca',
|
||||
'604-300-3333',
|
||||
'2012-01-10',
|
||||
'SW01 1015',
|
||||
'MATH'
|
||||
);
|
||||
|
||||
INSERT INTO student VALUES (
|
||||
'A10000001',
|
||||
'Tom',
|
||||
'Anderson',
|
||||
'tom.anderson@my.bcit.ca',
|
||||
'604-777-1111',
|
||||
'CST',
|
||||
'202550',
|
||||
'COMP'
|
||||
);
|
||||
|
||||
INSERT INTO student VALUES (
|
||||
'A10000002',
|
||||
'Sara',
|
||||
'Young',
|
||||
'sara.young@my.bcit.ca',
|
||||
'604-777-2222',
|
||||
'CST',
|
||||
'202550',
|
||||
'COMP'
|
||||
);
|
||||
|
||||
INSERT INTO student VALUES (
|
||||
'A10000003',
|
||||
'Reena',
|
||||
'Patel',
|
||||
'reena.patel@my.bcit.ca',
|
||||
'604-777-3333',
|
||||
'ACIT',
|
||||
'202550',
|
||||
'COMP'
|
||||
);
|
||||
|
||||
INSERT INTO student VALUES (
|
||||
'A10000004',
|
||||
'Min',
|
||||
'Chen',
|
||||
'min.chen@my.bcit.ca',
|
||||
'604-777-4444',
|
||||
'MATH',
|
||||
'202610',
|
||||
'MATH'
|
||||
);
|
||||
|
||||
INSERT INTO course VALUES (
|
||||
'COMP',
|
||||
2714,
|
||||
'Relational Database Systems',
|
||||
4.0,
|
||||
'COMP',
|
||||
'Core RDBMS course'
|
||||
);
|
||||
|
||||
INSERT INTO course VALUES (
|
||||
'COMP',
|
||||
1537,
|
||||
'Web Development 1',
|
||||
3.0,
|
||||
'COMP',
|
||||
'Intro to web dev'
|
||||
);
|
||||
|
||||
INSERT INTO course VALUES (
|
||||
'MATH',
|
||||
3042,
|
||||
'Discrete Mathematics',
|
||||
4.0,
|
||||
'MATH',
|
||||
'Proofs & structures'
|
||||
);
|
||||
|
||||
INSERT INTO course_offering (
|
||||
off_crs_code, off_term_code, off_section, off_type,
|
||||
off_prof, off_days, off_start_time, off_end_time,
|
||||
off_loc, off_capacity
|
||||
) VALUES (
|
||||
'COMP 2714',
|
||||
'202550',
|
||||
'LEC',
|
||||
'Lecture',
|
||||
'A00123456',
|
||||
'Mon,Wed',
|
||||
'09:30',
|
||||
'11:20',
|
||||
'SE12 240',
|
||||
'60'
|
||||
);
|
||||
|
||||
INSERT INTO course_offering (
|
||||
off_crs_code, off_term_code, off_section, off_type,
|
||||
off_prof, off_days, off_start_time, off_end_time,
|
||||
off_loc, off_capacity
|
||||
) VALUES (
|
||||
'COMP 2714',
|
||||
'202550',
|
||||
'L1',
|
||||
'Lab',
|
||||
'A00987654',
|
||||
'Fri',
|
||||
'12:30',
|
||||
'14:20',
|
||||
'SE12 260',
|
||||
'24'
|
||||
);
|
||||
|
||||
INSERT INTO enrollment VALUES (
|
||||
'A10000001',
|
||||
1,
|
||||
'Active',
|
||||
NULL
|
||||
);
|
||||
|
||||
INSERT INTO enrollment VALUES (
|
||||
'A10000002',
|
||||
1,
|
||||
'Active',
|
||||
NULL
|
||||
);
|
||||
|
||||
INSERT INTO enrollment VALUES (
|
||||
'A10000003',
|
||||
1,
|
||||
'Active',
|
||||
NULL
|
||||
);
|
||||
|
||||
INSERT INTO enrollment VALUES (
|
||||
'A10000001',
|
||||
2,
|
||||
'Active',
|
||||
NULL
|
||||
);
|
||||
|
||||
INSERT INTO enrollment VALUES (
|
||||
'A10000002',
|
||||
2,
|
||||
'Active',
|
||||
NULL
|
||||
);
|
||||
|
||||
-- TASK 2
|
||||
INSERT INTO student VALUES (
|
||||
'A01385066',
|
||||
'Braeden',
|
||||
'Sowinski',
|
||||
'bsowinski@my.bcit.ca',
|
||||
'778-208-8109',
|
||||
'CST',
|
||||
'202550',
|
||||
'COMP'
|
||||
);
|
||||
|
||||
INSERT INTO professor VALUES (
|
||||
'A11223344',
|
||||
'Jason',
|
||||
'Wilder',
|
||||
'jason.wilder@bcit.ca',
|
||||
'777-666-5555',
|
||||
'2020-01-01',
|
||||
'SE12 260',
|
||||
'COMP'
|
||||
);
|
||||
|
||||
INSERT INTO course_offering (
|
||||
off_crs_code, off_term_code, off_section, off_type,
|
||||
off_prof, off_days, off_start_time, off_end_time,
|
||||
off_loc, off_capacity
|
||||
) VALUES (
|
||||
'COMP 2714',
|
||||
'202550',
|
||||
'L2',
|
||||
'Lab',
|
||||
'A11223344',
|
||||
'Tue',
|
||||
'13:30',
|
||||
'15:20',
|
||||
'SE12 260',
|
||||
'20'
|
||||
);
|
||||
|
||||
INSERT INTO enrollment VALUES (
|
||||
'A01385066',
|
||||
3,
|
||||
'Active',
|
||||
NULL
|
||||
);
|
||||
|
||||
INSERT INTO enrollment VALUES (
|
||||
'A10000002',
|
||||
3,
|
||||
'Active',
|
||||
NULL
|
||||
);
|
||||
|
||||
-- TASK 3
|
||||
-- Insert location for update
|
||||
INSERT INTO location (loc_building, loc_room)
|
||||
VALUES ('SW01', '1015')
|
||||
ON CONFLICT DO NOTHING; -- if already exists, skip
|
||||
|
||||
UPDATE course_offering
|
||||
SET off_days = 'Thu',
|
||||
off_start_time = '15:30',
|
||||
off_end_time = '17:20',
|
||||
off_loc = 'SW01 1015'
|
||||
WHERE off_section = 'L1';
|
||||
|
||||
-- Update student A10000002 for course_offering 3
|
||||
UPDATE enrollment
|
||||
SET enr_status = 'Dropped'
|
||||
WHERE off_id = 3 -- L2 Lab Comp 2714
|
||||
AND stu_num = 'A10000002'; -- Sara Young
|
||||
|
||||
UPDATE enrollment
|
||||
SET enr_status = 'Active'
|
||||
WHERE off_id = 3 -- L2 Lab Comp 2714
|
||||
AND stu_num = 'A10000002'; -- Sara Young
|
||||
|
||||
-- Update grades
|
||||
UPDATE enrollment
|
||||
SET enr_final_grade = 'A'
|
||||
WHERE off_id = 1 -- Lecture Comp 2714
|
||||
AND stu_num = 'A10000001'; -- Tom Anderson
|
||||
|
||||
UPDATE enrollment
|
||||
SET enr_final_grade = 'A'
|
||||
WHERE off_id = 1 -- Lecture Comp 2714
|
||||
AND stu_num = 'A10000003'; -- Reena Patel
|
||||
|
||||
-- TASK 4
|
||||
|
||||
-- DELETE FROM department
|
||||
-- WHERE dep_code = 'COMP';
|
||||
|
||||
-- DELETE FROM course_offering
|
||||
-- WHERE off_section = 'L2';
|
||||
|
||||
-- DELETE FROM location
|
||||
-- WHERE loc_code = 'SE12 260';
|
||||
@@ -0,0 +1,14 @@
|
||||
Almost all the tables and or constraints caused errors, so I had to spend a lot of time, updating the lab5 schema sql file to accomodate the data given for lab 6 as well as update some constraints to ensure all the insertions worked as intended.
|
||||
|
||||
Here is an example of some of the error messages given while attemping to delete data in task 4 that is referenced by entities in other tables.
|
||||
|
||||
psql:lab6_dml.sql:322: ERROR: update or delete on table "department" violates foreign key constraint "professor_dep_code_fkey" on table "professor"
|
||||
DETAIL: Key (dep_code)=(COMP) is still referenced from table "professor".
|
||||
psql:lab6_dml.sql:325: ERROR: column "off_sectoin" does not exist
|
||||
LINE 2: WHERE off_sectoin = 'L2';
|
||||
^
|
||||
HINT: Perhaps you meant to reference the column "course_offering.off_section".
|
||||
psql:lab6_dml.sql:328: ERROR: update or delete on table "location" violates foreign key constraint "department_loc_code_fkey" on table "department"
|
||||
DETAIL: Key (loc_code)=(SE12 260) is still referenced from table "department".
|
||||
|
||||
Finally, I think the schema is much better not only to fit the data given but being correct and making sense logically on what data should be there, and what their constraints should be to better reflect the real world.
|
||||
@@ -0,0 +1,108 @@
|
||||
-- Braeden Sowinski
|
||||
-- Set 2D
|
||||
|
||||
SET search_path TO lab5;
|
||||
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'lab5';
|
||||
|
||||
-- Quick peek per table
|
||||
SELECT * FROM student LIMIT 5;
|
||||
|
||||
-- ### PART 1 - Basic SELECT ###
|
||||
|
||||
-- Q1.1 List all students’ first and last names.
|
||||
SELECT stu_fname, stu_lname FROM student;
|
||||
|
||||
-- Q1.2 List all courses (code + title).
|
||||
SELECT crs_code, crs_title FROM course;
|
||||
|
||||
-- Q1.3 Show all lab offerings for for COMP 2714 in Fall 2025 (days + start time).
|
||||
SELECT off_days, off_start_time
|
||||
FROM course_offering
|
||||
WHERE off_crs_code = 'COMP 2714'
|
||||
AND off_term_code = '202550' -- Fall 2025
|
||||
AND off_type = 'Lab';
|
||||
|
||||
-- Q1.4 Display all rows from your enrollment table.
|
||||
SELECT * FROM enrollment;
|
||||
|
||||
-- ### PART 2 - INNER JOIN Practice ###
|
||||
|
||||
-- Q2.1 List all students and the sections they are enrolled in. Include student name, section id, and term.
|
||||
SELECT student.stu_fname, course_offering.off_section, course_offering.off_term_code
|
||||
FROM student
|
||||
INNER JOIN enrollment
|
||||
ON student.stu_num = enrollment.stu_num
|
||||
INNER JOIN course_offering
|
||||
ON enrollment.off_id = course_offering.off_id;
|
||||
|
||||
-- Q2.2 Show all course offerings with their course titles.
|
||||
SELECT course_offering.off_id, course_offering.off_section, course_offering.off_type, course.crs_title
|
||||
FROM course_offering
|
||||
INNER JOIN course
|
||||
ON course_offering.off_crs_code = course.crs_code;
|
||||
|
||||
-- Q2.3 Display enrollments with the course title and the meeting days.
|
||||
SELECT enrollment.stu_num, enrollment.enr_status, course.crs_title, course_offering.off_days
|
||||
FROM enrollment
|
||||
INNER JOIN course_offering
|
||||
ON enrollment.off_id = course_offering.off_id
|
||||
INNER JOIN course
|
||||
ON course_offering.off_crs_code = course.crs_code;
|
||||
|
||||
-- ### PART 3 - FILTERING & SORTING ###
|
||||
|
||||
-- Q3.1 Students enrolled in Fall 2025 only (term code 202550).
|
||||
SELECT student.stu_fname, enrollment.enr_status, course_offering.off_term_code
|
||||
FROM student
|
||||
INNER JOIN enrollment
|
||||
ON student.stu_num = enrollment.stu_num
|
||||
INNER JOIN course_offering
|
||||
ON enrollment.off_id = course_offering.off_id
|
||||
WHERE off_term_code = '202550';
|
||||
|
||||
-- Q3.2 Courses whose title contains the word Database (case-insensitive).
|
||||
SELECT *
|
||||
FROM course
|
||||
WHERE LOWER(crs_title) LIKE LOWER('%database%');
|
||||
-- No contains? LOWER() ensures that it doesnt matter if upper or lower case
|
||||
|
||||
-- Q3.4 Students whose last name begins with C.
|
||||
SELECT *
|
||||
FROM student
|
||||
WHERE stu_lname LIKE 'C%';
|
||||
|
||||
-- ### PART 4 - OUTER JOINs & NULLs
|
||||
|
||||
-- Q4.1 All students with their enrollment info, including students with no enrollments (use LEFT JOIN).
|
||||
SELECT student.stu_fname, enrollment.*
|
||||
FROM student
|
||||
LEFT JOIN enrollment
|
||||
ON student.stu_num = enrollment.stu_num;
|
||||
|
||||
-- Q4.2 Courses not offered in the current term.
|
||||
SELECT course.crs_title, course.crs_subject, course.crs_credits
|
||||
FROM course
|
||||
LEFT JOIN course_offering
|
||||
ON course_offering.off_crs_code = course.crs_code
|
||||
WHERE course_offering.off_term_code IS NULL;
|
||||
|
||||
-- ### REFLECTION ###
|
||||
--
|
||||
-- Yes, all of the row counts make sense, there may
|
||||
-- be some duplicatoin. For example, when we are
|
||||
-- getting all student ids, and their enrollments,
|
||||
-- there may be duplicate enrollment data.
|
||||
-- i.e. two students are enrolled in the same
|
||||
-- course_offering. However, we since we are showing
|
||||
-- the student_id we are able to tell them apart.
|
||||
|
||||
-- I dont think distinct would change the result
|
||||
-- in the example above, there is student x enrolled
|
||||
-- in class A, and student y enrolled in class A too.
|
||||
-- Those are already distinct.
|
||||
|
||||
-- Yes I think I am selecting the minimul necessary
|
||||
-- columns, only showing relavent related information.
|
||||
@@ -0,0 +1,9 @@
|
||||
Yes, all of the row counts make sense, there may be some duplicatoin.
|
||||
For example, when we are getting all student ids, and their enrollments, there may be duplicate enrollment data.
|
||||
i.e. two students are enrolled in the same course_offering. However, we since we are showing the student_id we are able to tell them apart.
|
||||
|
||||
I dont think distinct would change the result in the example above, there is student x enrolled in class A, and student y enrolled in class A too. Those are already distinct.
|
||||
|
||||
I think for the most part I am selecting the minimul necessary columns, only showing relavent related information.
|
||||
|
||||
Unless asked to show all data of a table.
|
||||
Reference in new issue
Block a user