PRAGMA forien_keys = ON;

PRAGMA forien_keys;

CREATE TABLE instructors (
                             instructor_id INTEGER PRIMARY KEY AUTOINCREMENT,
                             first_name TEXT NOT NULL,
                             last_name TEXT NOT NULL,
                             email TEXT NOT NULL UNIQUE
);

CREATE TABLE students (
                          student_id INTEGER PRIMARY KEY,
                          first_name TEXT NOT NULL,
                          last_name TEXT NOT NULL,
                          email TEXT NOT NULL UNIQUE,
                          major TEXT DEFAULT "Undeclared"
);


CREATE TABLE courses (
                         course_id INTEGER PRIMARY KEY,
                         title TEXT NOT NULL,
                         department TEXT NOT NULL,
                         credits INTEGER,
                         instructor_id INTEGER ,

                         CONSTRAINT fk_courses_instructor FOREIGN KEY(instructor_id) REFERENCES instructors(instructor_id)
);

-- 修改 Courses 表中 instructor_id 的外键约束。要求当 Instructors 表中的某位讲师记录被删除时，Courses 表中由该讲师授课的课程的 instructor_id 字段应自动被设置为 NULL 。
CREATE TABLE courses_back AS SELECT * FROM courses;
DROP TABLE courses;
CREATE TABLE courses (
                       course_id INTEGER PRIMARY KEY,
                       title TEXT NOT NULL,
                       department TEXT NOT NULL,
                       credits INTEGER,
                       instructor_id INTEGER ,

                       CONSTRAINT fk_courses_instructor FOREIGN KEY(instructor_id) REFERENCES instructors(instructor_id) ON DELETE SET NULL
    );

INSERT INTO courses SELECT * FROM courses_back;
DROP TABLE courses_back;

-- 创建一个名为 Enrollments 的连接表，用于记录学生选修课程的情况。该表应包含：
--
-- student_id: 整数类型。
--
-- course_id: 整数类型。
--
-- grade: 文本类型，用于存储成绩（如 'A', 'B+', 'C' 等）。
--
-- 将 student_id 和 course_id 的组合设置为主键（复合主键）。
create table enrollments (
    student_id INTEGER NOT NULL,
    course_id INTEGER NOT NULL,
    grade TEXT,

    -- 想象一下你的身份证号（假设前6位是地区码，后8位是个人编码）。单看地区码无法确定你是谁（一个地区有千万人），单看个人编码也可能重复（不同地区可能有相同个人编码）。但“地区码+个人编码”的组合就能在全国范围内唯一锁定你这个人。这个组合就是“复合主键”。
    -- 定义复合主键：一个学生不能多次选修同一门课程
    PRIMARY KEY (student_id, course_id),
    -- 要求当 Students 表中的某个学生记录被删除时，该学生所有的选课记录也应自动从 Enrollments 表中被删除（级联删除）
    FOREIGN KEY (student_id) REFERENCES students(student_id) on delete cascade ,
    FOREIGN KEY (course_id) REFERENCES courses(course_id)
);
PRAGMA foreign_keys = ON;

-- 使用 ALTER TABLE 命令为 Instructors 表添加一个新列，名为 office_number，类型为 TEXT。
alter table instructors add column office_number TEXT;

-- 使用 ALTER TABLE 命令将 Enrollments 表重命名为 Student_Enrollments。
alter table enrollments rename to student_enrollments;

drop table student_enrollments;
drop table sqlite_master;

-- 创建一个名为 Temp_Table 的临时表（列定义不限），然后写出删除该表的命令。
-- 临时表最大的优点是无需手动管理清理，断开连接后自动消失，避免了垃圾数据累积。 wdd:有何意义？

-- 向 Instructors 表中插入以下三位讲师的数据：
--
-- (1, 'Alan', 'Turing', 'alan.turing@bletchley.edu', 'B-101')
--
-- (2, 'Grace', 'Hopper', 'grace.hopper@yale.edu', 'C-203')
--
-- (3, 'John', 'von Neumann', 'john.vn@ias.edu', 'A-305')

insert into instructors values
                            (1, 'Alan', 'Turing', 'alan.turing@bletchley.edu', 'B-101'),
                           (2, 'Grace', 'Hopper', 'grace.hopper@yale.edu', 'C-203'),
                           (3, 'John', 'von Neumann', 'john.vn@ias.edu', 'A-305');


INSERT INTO students VALUES
   (101, 'Alice', 'Smith', 'alice.smith@university.edu', 'Computer Science'),
   (102, 'Bob', 'Johnson', 'bob.johnson@university.edu', 'Physics'),
   (103, 'Charlie', 'Brown', 'charlie.brown@university.edu', 'History'),
   (104, 'Diana', 'Prince', 'diana.prince@university.edu', 'Computer Science'),
   (105, 'Eve', 'Adams', 'eve.adams@university.edu', 'Physics');


INSERT INTO courses (course_id, title, department, credits, instructor_id) VALUES
                                                                               (201, 'Introduction to CS', 'CSCI', 3, 1),
                                                                               (202, 'Advanced Compilers', 'CSCI', 4, 2),
                                                                               (203, 'Game Theory', 'MATH', 3, 3),
                                                                               (204, 'Databases', 'CSCI', 4, 1),
                                                                               (205, 'Quantum Mechanics', 'PHYS', 4, NULL);

INSERT INTO enrollments (student_id, course_id, grade) VALUES
                                                                   (101, 201, 'A'),
                                                                   (101, 204, 'B+'),
                                                                   (102, 205, 'A-'),
                                                                   (103, 203, 'B'),
                                                                   (104, 201, 'C'),
                                                                   (104, 202, 'A');

-- 测试 NOT NULL 约束：尝试向 Instructors 表中插入一条记录，但 first_name 字段留空。此操作预期会失败。请写出这条 INSERT 语句。
insert into instructors (instructor_id, first_name, last_name, office_number, email) values (233, null, "yes", "CS-1", "ok@qq.com");

-- 测试 FOREIGN KEY 约束：尝试向 Courses 表中插入一门新课程，其 instructor_id 为999，而这个ID在 Instructors 表中并不存在。此操作预期会因违反外键约束而失败。请写出这条 INSERT 语句。
insert into courses (course_id, title, department, credits, instructor_id) values (123, "测试课程", "fts3tokenize", 12, 999);

-- Alan Turing博士更换了办公室。请使用 UPDATE 语句，将他的 office_number 更新为 'B-105'。
update instructors set office_number="B-105" where first_name="Alan" and last_name="Turing";

-- 学校决定将 'CSCI' 系的缩写统一更改为 'COMP'。请使用 UPDATE 语句更新 Courses 表中所有 'CSCI' 系的课程。
update courses set title="COMP" where title = "CSCI";

-- 测试 ON DELETE CASCADE：学生 'Bob Johnson' (student_id=102) 退学。请从 Students 表中删除他的记录。删除后，请查询 Student_Enrollments 表，验证他的选课记录是否也已被自动删除
delete from students where student_id=102;

-- 连表查询 查询学生'Bob Johnson' (student_id=102) 选取的所有课程信息
select e.student_id, e.course_id, c.title, c.department, c.credits from enrollments e
    INNER JOIN courses c on e.course_id = c.course_id where e.student_id = 102;

-- 测试 ON DELETE SET NULL：讲师 'Grace Hopper' (instructor_id=2) 离职。请从 Instructors 表中删除她的记录。删除后，请查询 Courses 表，验证她所教授课程的 instructor_id 是否已变为 NULL。
select * from instructors i inner join courses c on i.instructor_id = c.instructor_id where i.instructor_id =2;

delete from instructors where instructor_id=2;

-- 删除 Student_Enrollments 表中所有成绩为 'C' 的记录。
select * from enrollments;
delete from enrollments where grade = 'C';

-- 查询并显示 Students 表中的所有列及所有行。
select * from students;


-- 查询所有讲师的姓（last_name）和名（first_name）。
select last_name, first_name from instructors;

-- 查询所有属于 'COMP' 系（假设已在DML部分更新）的课程名称（title）。
select title from courses where  department = 'COMP';


-- 查询所有专业为 'Physics' 的学生信息，并按姓氏（last_name）升序排列。
select * from students where major = 'Physics' order by last_name asc ;

-- 查询学分（credits）最高的3门课程的所有信息。
select * from courses order by credits desc limit 3;

-- 查询 Students 表中所有不重复的专业（major）名称。
select distinct major from students;

-- 查询课程名称（title）中包含 'Intro' 关键字的所有课程。
select * from courses where title like  '%Intro%';

-- 查询专业为 'History' 或 'Physics' 的所有学生信息。
select * from students where major = 'History' or 'Physics';

-- 查询所有办公室编号（office_number）未被指定的讲师。
select * from instructors where office_number = '' or null;

-- 查询所有学分在3到4之间（包含3和4）的课程名称和学分。
select * from courses where credits between 3 and 4;


-- 统计 Students 表中共有多少名学生。
select count(*) from students;

-- 计算 Courses 表中所有课程的平均学分是多少。
select avg(credits) avg_credits from courses;

-- 统计选修了课程ID为201（'Introduction to CS'）的学生总人数。
select count(student_id) from enrollments where course_id = 201;

-- 按专业（major）分组，统计每个专业的学生人数。
select count(student_id) student_count, major from students group by major;

-- 按系别（department）分组，统计每个系别开设的课程数量。
select count(course_id) course_count, courses.department from courses group by  department;

-- 查询学生人数超过1人的专业名称以及对应的人数。
SELECT major, COUNT(*) FROM Students GROUP BY major HAVING COUNT(*) > 1;;

-- 按课程（course_id）分组，计算每门课程的平均成绩（提示：这在当前数据结构下无法直接计算，但请思考如何统计选课人数）。
--
-- 请统计每门课程的选课人数。
select c.course_id, count(e.student_id), e.grade from courses c inner join enrollments e on c.course_id = e.course_id group by c.course_id;

-- 查询开设课程总数超过1门的讲师ID及其开设的课程数。
select i.instructor_id, count(c.course_id) from instructors i inner join courses c on i.instructor_id = c.instructor_id group by i.instructor_id;

-- 找出 Courses 表中学分最高和最低的课程的学分值。
-- select credits from courses group by credits ;
-- 找出学分最高和最低的值
SELECT
    MAX(credits) AS highest_credits,
    MIN(credits) AS lowest_credits
FROM courses;
-- 如果想要同时查看这些极值对应的课程信息
SELECT *
FROM courses
WHERE credits = (SELECT MAX(credits) FROM courses)
   OR credits = (SELECT MIN(credits) FROM courses);

-- 统计所有 'COMP' 系课程的总学分。
select sum(credits) from courses where department='CSCI';

-- 使用 INNER JOIN 查询所有选修了 'Introduction to CS' 这门课的学生的姓和名。
select * from courses c inner join enrollments e on c.course_id = e.course_id inner join students s on s.student_id = e.student_id where c.title = 'Introduction to CS';

-- 使用 INNER JOIN 连接 Student_Enrollments 和 Students 表，列出每条选课记录对应的学生全名（姓和名拼接）和成绩。
select s.last_name || ' ' || s.first_name as full_name, e.grade from enrollments e inner join students s on s.student_id = e.student_id;


-- 使用 INNER JOIN 连接 Courses 和 Instructors 表，列出每位讲师的全名以及他们所教授的课程名称。
select  s.last_name || ' ' || s.first_name as full_name, c.title from instructors s inner join courses c on s.instructor_id = c.instructor_id;

-- LEFT JOIN 应用：查询所有讲师的全名，以及他们教授的课程名称。即使某位讲师没有教授任何课程，也需要显示在结果中（其课程名称显示为 NULL）。
select  s.last_name || ' ' || s.first_name as full_name,  c.title  from instructors s left join courses c on s.instructor_id = c.instructor_id;

-- LEFT JOIN 应用：查询所有没有教授任何课程的讲师的全名。
select  s.last_name || ' ' || s.first_name as full_name from instructors s left join courses c on s.instructor_id = c.instructor_id where c.instructor_id is null;

-- LEFT JOIN 应用：查询所有学生的姓名，以及他们选修的课程名称。即使某个学生没有选修任何课程，也需要显示在结果中。
select s.last_name, s.first_name, c.title from students s left join enrollments e on s.student_id = e.student_id left join courses c on e.course_id = c.course_id;

-- LEFT JOIN 应用：查询所有没有选修任何课程的学生的姓名。
select s.last_name, s.first_name , s.student_id from students s where  s.student_id not in (select student_id
                                                                                            from enrollments
    );

-- 使用子查询，查询由 'Alan Turing' 教授的所有课程的名称。
select c.title from courses c where instructor_id = (
    select instructor_id from instructors where first_name = 'Alan' and last_name = 'Turing'
    );

-- 使用子查询，查询选修了至少一门 'COMP' 系课程的所有学生的姓名。
select s.first_name, s.last_name from students s where s.student_id = (
    select student_id from enrollments where course_id = (
        select course_id from courses where department = 'CSCI'
        )
    );

select count(student_id) from enrollments where course_id = (
    select course_id from courses where department = 'CSCI'
);

select course_id from courses where department = 'CSCI';

-- 查询选课数量最多的学生的姓名。
select students.first_name, students.last_name
from students where student_id = (select student_id from enrollments group by student_id order by count(course_id) limit 1);

-- 使用 CASE 语句，查询所有学生的姓名和专业，并添加一列名为 remark 的备注。如果专业是 'Computer Science'，备注为 'Tech Major'；如果专业是 'Physics'，备注为 'Science Major'；否则备注为 'Arts & Humanities'。
select students.first_name, students.last_name

-- 逻辑执行顺序理解：尝试按专业统计学生人数，并将统计结果列命名为 student_count。然后，使用 WHERE student_count > 1 来筛选结果。这个查询会失败。请解释为什么会失败，并写出使用 HAVING 子句的正确查询 。