Нужно ли мне выполнять объединение 4 таблиц для выполнения этого SQL-запроса или есть более простой метод?

#mysql #sql

#mysql #sql

Вопрос:

В настоящее время мне нужно сделать следующее:

Найдите имена всех курсов и студентов, зачисленных на них, которые проходят в пятницу днем, и на них записано не менее 2 студентов.

Я думаю, что мне нужно объединить таблицы под названием student, takes, course, section и time_slot вместе и оттуда выполнить SQL-запрос, но мне это кажется излишним.

Сначала я бы получил список всех курсов и всех имен студентов, которые проходят курсы, объединив таблицы takes и students .

Затем я бы нашел все курсы, которые проводятся в пятницу днем, используя time_slot_id, который должен быть «D» ИЛИ «F» ИЛИ «G», а день будет «F» для обозначения пятницы. Тогда я бы сопоставил временной интервал с разделом.

После этого я застрял.

Вот что я пробовал:

 SELECT name, course_ID FROM takes JOIN student ON takes.id = student.ID WHERE count(course_ID) > 1;
  

и

 SELECT course_id
FROM takes JOIN student ON takes.id = student.ID
GROUP BY course_id
HAVING COUNT(*) > 1;
  

Нижний запрос работает, но не содержит имен учащихся, а верхний намного ближе к тому, что мне нужно, но возвращает ошибку.

Вот полный код MySQL, который у меня есть.

 CREATE TABLE time_slot(
    time_slot_id VARCHAR(100) NOT NULL,
    day VARCHAR(100) NOT NULL,
    start_hour TIME NOT NULL,
    start_min TIME NOT NULL,
    end_hour TIME NOT NULL,
    end_min TIME NOT NULL,
    PRIMARY KEY (time_slot_id, day, start_hour, start_min)
    );

CREATE TABLE department(
    dept_name VARCHAR(100) NOT NULL,
    building VARCHAR(100) NOT NULL,
    budget DECIMAL(10, 2) UNSIGNED,
    PRIMARY KEY(dept_name)
    );

CREATE TABLE student(
    ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    dept_name VARCHAR(100) NOT NULL,
    tot_cred SMALLINT NOT NULL,
    PRIMARY KEY (ID),
    FOREIGN KEY (dept_name) REFERENCES department(dept_name)
    );


CREATE TABLE instructor(
    ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    dept_name VARCHAR(100) NOT NULL,
    salary DECIMAL(10, 2) UNSIGNED NOT NULL,
    PRIMARY KEY (ID),
    FOREIGN KEY (dept_name) REFERENCES department(dept_name)
    );

CREATE TABLE course(
    course_id VARCHAR(100) NOT NULL,
    title VARCHAR(255) NOT NULL,
    dept_name VARCHAR(100) NOT NULL,
    cedits SMALLINT UNSIGNED NOT NULL,
    PRIMARY KEY (course_id),
    FOREIGN KEY (dept_name) REFERENCES department(dept_name)
    );

CREATE TABLE prereq(
    course_id VARCHAR(100) NOT NULL,
    prereq_id VARCHAR(100) NOT NULL,
    PRIMARY KEY(course_id, prereq_id),
    FOREIGN KEY(course_id) REFERENCES course(course_id)
    );


CREATE TABLE classroom(
    building VARCHAR(100) NOT NULL,
    room_no VARCHAR(100) NOT NULL,
    capacity SMALLINT NOT NULL,
    PRIMARY KEY (building, room_no)
    );


CREATE TABLE section(
    course_id VARCHAR(100) NOT NULL,
    sec_id VARCHAR(100) NOT NULL,
    semester VARCHAR(100) NOT NULL,
    year SMALLINT UNSIGNED NOT NULL,
    building VARCHAR(100) NOT NULL,
    room_no VARCHAR(100) NOT NULL,
    time_slot_id VARCHAR(100) NOT NULL,
    PRIMARY KEY (course_id, sec_id, semester, year),
    FOREIGN KEY (course_id) REFERENCES course(course_id),
    FOREIGN KEY (building,room_no) REFERENCES classroom(building,room_no),
    FOREIGN KEY (time_slot_id) REFERENCES time_slot(time_slot_id)
    );

CREATE TABLE takes(
    ID INT UNSIGNED,
    course_id VARCHAR(100) NOT NULL,
    sec_id VARCHAR(100) NOT NULL,
    semester VARCHAR(100) NOT NULL,
    year SMALLINT UNSIGNED NOT NULL,
    grade VARCHAR(100),
    PRIMARY KEY (ID, course_id, sec_id, semester, year),
    FOREIGN KEY (ID) REFERENCES student(ID),
    FOREIGN KEY (course_id,sec_id,semester,year) REFERENCES section(course_id,sec_id,semester,year)

    );


CREATE TABLE teaches(
    ID INT UNSIGNED,
    course_id VARCHAR(100), 
    sec_id VARCHAR(100),
    semester VARCHAR(100),
    year SMALLINT UNSIGNED,
    PRIMARY KEY(ID, course_id, sec_id, semester, year),
    FOREIGN KEY(ID) REFERENCES instructor(ID),
FOREIGN KEY (course_id,sec_id,semester,year) REFERENCES section(course_id,sec_id,semester,year)
    );

CREATE TABLE advisor(
    s_id INT UNSIGNED NOT NULL,
    i_id INT UNSIGNED NOT NULL,
    PRIMARY KEY (s_id),
    FOREIGN KEY (s_id) REFERENCES student(ID),
    FOREIGN KEY (i_id) REFERENCES instructor(ID)
    );


insert into classroom values ('Packard', '101', '500');
insert into classroom values ('Painter', '514', '10');
insert into classroom values ('Taylor', '3128', '70');
insert into classroom values ('Watson', '100', '30');
insert into classroom values ('Watson', '120', '50');
insert into department values ('Biology', 'Watson', '90000');
insert into department values ('Comp. Sci.', 'Taylor', '100000');
insert into department values ('Elec. Eng.', 'Taylor', '85000');
insert into department values ('Finance', 'Painter', '120000');
insert into department values ('History', 'Painter', '50000');
insert into department values ('Music', 'Packard', '80000');
insert into department values ('Physics', 'Watson', '70000');
insert into course values ('BIO-101', 'Intro. to Biology', 'Biology', '4');
insert into course values ('BIO-301', 'Genetics', 'Biology', '4');
insert into course values ('BIO-399', 'Computational Biology', 'Biology', '3');
insert into course values ('CS-101', 'Intro. to Computer Science', 'Comp. Sci.', '4');
insert into course values ('CS-190', 'Game Design', 'Comp. Sci.', '4');
insert into course values ('CS-315', 'Robotics', 'Comp. Sci.', '3');
insert into course values ('CS-319', 'Image Processing', 'Comp. Sci.', '3');
insert into course values ('CS-347', 'Database System Concepts', 'Comp. Sci.', '3');
insert into course values ('EE-181', 'Intro. to Digital Systems', 'Elec. Eng.', '3');
insert into course values ('FIN-201', 'Investment Banking', 'Finance', '3');
insert into course values ('HIS-351', 'World History', 'History', '3');
insert into course values ('MU-199', 'Music Video Production', 'Music', '3');
insert into course values ('PHY-101', 'Physical Principles', 'Physics', '4');
insert into instructor values ('10101', 'Srinivasan', 'Comp. Sci.', '65000');
insert into instructor values ('12121', 'Wu', 'Finance', '90000');
insert into instructor values ('15151', 'Mozart', 'Music', '40000');
insert into instructor values ('22222', 'Einstein', 'Physics', '95000');
insert into instructor values ('32343', 'El Said', 'History', '60000');
insert into instructor values ('33456', 'Gold', 'Physics', '87000');
insert into instructor values ('45565', 'Katz', 'Comp. Sci.', '75000');
insert into instructor values ('58583', 'Califieri', 'History', '62000');
insert into instructor values ('76543', 'Singh', 'Finance', '80000');
insert into instructor values ('76766', 'Crick', 'Biology', '72000');
insert into instructor values ('83821', 'Brandt', 'Comp. Sci.', '92000');
insert into instructor values ('98345', 'Kim', 'Elec. Eng.', '80000');
insert into time_slot values ('A', 'M', '8', '0', '8', '50');
insert into time_slot values ('A', 'W', '8', '0', '8', '50');
insert into time_slot values ('A', 'F', '8', '0', '8', '50');
insert into time_slot values ('B', 'M', '9', '0', '9', '50');
insert into time_slot values ('B', 'W', '9', '0', '9', '50');
insert into time_slot values ('B', 'F', '9', '0', '9', '50');
insert into time_slot values ('C', 'M', '11', '0', '11', '50');
insert into time_slot values ('C', 'W', '11', '0', '11', '50');
insert into time_slot values ('C', 'F', '11', '0', '11', '50');
insert into time_slot values ('D', 'M', '13', '0', '13', '50');
insert into time_slot values ('D', 'W', '13', '0', '13', '50');
insert into time_slot values ('D', 'F', '13', '0', '13', '50');
insert into time_slot values ('E', 'T', '10', '30', '11', '45');
insert into time_slot values ('E', 'R', '10', '30', '11', '45');
insert into time_slot values ('F', 'T', '14', '30', '15', '45');
insert into time_slot values ('F', 'R', '14', '30', '15', '45');
insert into time_slot values ('G', 'M', '16', '0', '16', '50');
insert into time_slot values ('G', 'W', '16', '0', '16', '50');
insert into time_slot values ('G', 'F', '16', '0', '16', '50');
insert into time_slot values ('H', 'W', '10', '0', '12', '30');
insert into section values ('BIO-101', '1', 'Summer', '2009', 'Painter', '514', 'B');
insert into section values ('BIO-301', '1', 'Summer', '2010', 'Painter', '514', 'A');
insert into section values ('CS-101', '1', 'Fall', '2009', 'Packard', '101', 'H');
insert into section values ('CS-101', '1', 'Spring', '2010', 'Packard', '101', 'F');
insert into section values ('CS-190', '1', 'Spring', '2009', 'Taylor', '3128', 'E');
insert into section values ('CS-190', '2', 'Spring', '2009', 'Taylor', '3128', 'A');
insert into section values ('CS-315', '1', 'Spring', '2010', 'Watson', '120', 'D');
insert into section values ('CS-319', '1', 'Spring', '2010', 'Watson', '100', 'B');
insert into section values ('CS-319', '2', 'Spring', '2010', 'Taylor', '3128', 'C');
insert into section values ('CS-347', '1', 'Fall', '2009', 'Taylor', '3128', 'A');
insert into section values ('EE-181', '1', 'Spring', '2009', 'Taylor', '3128', 'C');
insert into section values ('FIN-201', '1', 'Spring', '2010', 'Packard', '101', 'B');
insert into section values ('HIS-351', '1', 'Spring', '2010', 'Painter', '514', 'C');
insert into section values ('MU-199', '1', 'Spring', '2010', 'Packard', '101', 'D');
insert into section values ('PHY-101', '1', 'Fall', '2009', 'Watson', '100', 'A');
insert into teaches values ('10101', 'CS-101', '1', 'Fall', '2009');
insert into teaches values ('10101', 'CS-315', '1', 'Spring', '2010');
insert into teaches values ('10101', 'CS-347', '1', 'Fall', '2009');
insert into teaches values ('12121', 'FIN-201', '1', 'Spring', '2010');
insert into teaches values ('15151', 'MU-199', '1', 'Spring', '2010');
insert into teaches values ('22222', 'PHY-101', '1', 'Fall', '2009');
insert into teaches values ('32343', 'HIS-351', '1', 'Spring', '2010');
insert into teaches values ('45565', 'CS-101', '1', 'Spring', '2010');
insert into teaches values ('45565', 'CS-319', '1', 'Spring', '2010');
insert into teaches values ('76766', 'BIO-101', '1', 'Summer', '2009');
insert into teaches values ('76766', 'BIO-301', '1', 'Summer', '2010');
insert into teaches values ('83821', 'CS-190', '1', 'Spring', '2009');
insert into teaches values ('83821', 'CS-190', '2', 'Spring', '2009');
insert into teaches values ('83821', 'CS-319', '2', 'Spring', '2010');
insert into teaches values ('98345', 'EE-181', '1', 'Spring', '2009');
insert into student values ('00128', 'Zhang', 'Comp. Sci.', '102');
insert into student values ('12345', 'Shankar', 'Comp. Sci.', '32');
insert into student values ('19991', 'Brandt', 'History', '80');
insert into student values ('23121', 'Chavez', 'Finance', '110');
insert into student values ('44553', 'Peltier', 'Physics', '56');
insert into student values ('45678', 'Levy', 'Physics', '46');
insert into student values ('54321', 'Williams', 'Comp. Sci.', '54');
insert into student values ('55739', 'Sanchez', 'Music', '38');
insert into student values ('70557', 'Snow', 'Physics', '0');
insert into student values ('76543', 'Brown', 'Comp. Sci.', '58');
insert into student values ('76653', 'Aoi', 'Elec. Eng.', '60');
insert into student values ('98765', 'Bourikas', 'Elec. Eng.', '98');
insert into student values ('98988', 'Tanaka', 'Biology', '120');
insert into takes values ('00128', 'CS-101', '1', 'Fall', '2009', 'A');
insert into takes values ('00128', 'CS-347', '1', 'Fall', '2009', 'A-');
insert into takes values ('12345', 'CS-101', '1', 'Fall', '2009', 'C');
insert into takes values ('12345', 'CS-190', '2', 'Spring', '2009', 'A');
insert into takes values ('12345', 'CS-315', '1', 'Spring', '2010', 'A');
insert into takes values ('12345', 'CS-347', '1', 'Fall', '2009', 'A');
insert into takes values ('19991', 'HIS-351', '1', 'Spring', '2010', 'B');
insert into takes values ('23121', 'FIN-201', '1', 'Spring', '2010', 'C ');
insert into takes values ('44553', 'PHY-101', '1', 'Fall', '2009', 'B-');
insert into takes values ('45678', 'CS-101', '1', 'Fall', '2009', 'F');
insert into takes values ('45678', 'CS-101', '1', 'Spring', '2010', 'B ');
insert into takes values ('45678', 'CS-319', '1', 'Spring', '2010', 'B');
insert into takes values ('54321', 'CS-101', '1', 'Fall', '2009', 'A-');
insert into takes values ('54321', 'CS-190', '2', 'Spring', '2009', 'B ');
insert into takes values ('55739', 'MU-199', '1', 'Spring', '2010', 'A-');
insert into takes values ('76543', 'CS-101', '1', 'Fall', '2009', 'A');
insert into takes values ('76543', 'CS-319', '2', 'Spring', '2010', 'A');
insert into takes values ('76653', 'EE-181', '1', 'Spring', '2009', 'C');
insert into takes values ('98765', 'CS-101', '1', 'Fall', '2009', 'C-');
insert into takes values ('98765', 'CS-315', '1', 'Spring', '2010', 'B');
insert into takes values ('98988', 'BIO-101', '1', 'Summer', '2009', 'A');
insert into takes values ('98988', 'BIO-301', '1', 'Summer', '2010', null);
insert into advisor values ('00128', '45565');
insert into advisor values ('12345', '10101');
insert into advisor values ('23121', '76543');
insert into advisor values ('44553', '22222');
insert into advisor values ('45678', '22222');
insert into advisor values ('76543', '45565');
insert into advisor values ('76653', '98345');
insert into advisor values ('98765', '98345');
insert into advisor values ('98988', '76766');
insert into prereq values ('BIO-301', 'BIO-101');
insert into prereq values ('BIO-399', 'BIO-101');
insert into prereq values ('CS-190', 'CS-101');
insert into prereq values ('CS-315', 'CS-101');
insert into prereq values ('CS-319', 'CS-101');
insert into prereq values ('CS-347', 'CS-101');
insert into prereq values ('EE-181', 'PHY-101');
  

Комментарии:

1. И как мы узнаем, что представляют «D», «F» или «G»?

2. D F G — это все time_slot_id . Например, D представляет урок, который начинается с 1300 и заканчивается на 1350

3. Я вижу, так что это все «дневные» слоты.

4. да, D, G, F — это все дневные слоты.

5. Ну, что произойдет, если вы начнете с таблицы разделов?

Ответ №1:

Хорошо … давайте создадим это, используя вашу стратегию.

Сначала я бы получил список всех курсов и всех имен студентов, которые проходят курсы, объединив таблицы takes и students .

Приведенный ниже запрос является правильным началом для этого — он находит все курсы, на которых обучается более одного студента.

 SELECT course_id
FROM takes JOIN student ON takes.id = student.ID
GROUP BY course_id
HAVING COUNT(*) > 1;
  

Важным предостережением к вышесказанному является то, что не имеет значения, в каком семестре / etc студенты это делают — просто на курс было записано более одного человека в любое время, в любом временном интервале и т.д.

Чтобы получить другую информацию (названия курсов и студентов), вы просто свяжете это с таблицами course и takes amp; student, например,

 SELECT  c.title AS Course_Title, s.name AS Student_Name
  FROM  course AS c
        INNER JOIN takes AS t ON c.course_id = t.course_id
        INNER JOIN student AS s ON t.ID = s.ID
        INNER JOIN 
          (SELECT course_id
             FROM takes JOIN student ON takes.id = student.ID
             GROUP BY course_id
             HAVING COUNT(*) > 1
          ) AS courses_2plus_students ON c.course_id = courses_2plus_students.course_id;
  

Конечно, вы могли бы изменить приведенное выше, чтобы вложенный запрос находился в предложении WHERE или в CTE.

Обратите внимание, что существует более эффективный способ выполнения вышеуказанного с использованием оконных функций, но я предполагаю, что на данный момент это слишком далеко.

Однако, как вы сказали в своей стратегии — это не весь ответ — нам нужно отфильтровать курсы.

Затем я бы нашел все курсы, которые проводятся в пятницу днем, используя time_slot_id, который должен быть «D» ИЛИ «F» ИЛИ «G», а день будет «F» для обозначения пятницы. Тогда я бы сопоставил временной интервал с разделом.

Я предполагаю, что вы хотите, чтобы временные интервалы вычислялись, а не жестко кодировались (в случае, если вы добавляете новые временные интервалы, например, тот, который выполняется в понедельник, вторник, четверг утром). Таким образом, я определю «дневной» слот как тот, который начинается в 12:00 или после, но до 6:00 вечера.

Мы можем получить соответствующие временные интервалы с помощью следующего

 SELECT    DISTINCT ts.time_slot_id
  FROM    time_slot ts
  WHERE   ts.`day` = 'F'
          AND ts.start_hour >= 12 and ts.start_hour < 18;
  

Приведенное выше должно привести к ‘D’ и ‘G’ (обратите внимание, что F не учитывается в соответствии с вашими данными). Я использовал DISTINCT в приведенном выше для удаления дубликатов в случае, если данный временной интервал имеет двойной класс, например, 2 класса в данный день.

Затем нам нужны соответствующие идентификаторы course_ids, которые мы получаем, присоединяясь к приведенному выше разделу to (и удаляя ссылку на time_slot_id, поскольку она нам больше не нужна).

 SELECT    DISTINCT sec.course_id
  FROM    section sec
          INNER JOIN time_slot ts ON sec.time_slot_id = ts.time_slot_id
  WHERE   ts.`day` = 'F'
          AND ts.start_hour >= 12 and ts.start_hour < 18;
  

Теперь все, что нам нужно сделать, это отфильтровать курсы сверху, используя разделы сверху. Итак, SQL для получения (начального) ответа…

 SELECT  c.title AS Course_Title, s.name AS Student_Name
  FROM  course AS c
        INNER JOIN takes AS t ON c.course_id = t.course_id
        INNER JOIN student AS s ON t.ID = s.ID
        INNER JOIN 
          (SELECT course_id
             FROM takes JOIN student ON takes.id = student.ID
             GROUP BY course_id
             HAVING COUNT(*) > 1
          ) AS courses_2plus_students ON c.course_id = courses_2plus_students.course_id
        INNER JOIN
           (SELECT    DISTINCT sec.course_id
              FROM    section sec
                      INNER JOIN time_slot ts ON sec.time_slot_id = ts.time_slot_id
              WHERE   ts.`day` = 'F'
                      AND ts.start_hour >= 12 and ts.start_hour < 18
            ) AS Friday_afternoon_courses on c.course_id = Friday_afternoon_courses.course_id;
  

Еще раз, вы могли бы использовать WHERE или CTE etc вместо подзапроса.

Вот db<>fiddle с каждым из шагов, описанных выше. Обратите внимание, что первый раздел скрыт — он содержит ваши структуры данных и данные (но с заданным временем int прохождения, а не time ).

Примечание — и это важное замечание — вам нужно быть очень осторожным в отношении того, что это представляет.

  • Курсы могут проводиться в разные временные интервалы и в разные семестры. Например, CS-101 поставляется осенью 2009 года в time_slot H; он также поставляется весной 2010 года с time_slot F.
  • Приведенный выше ответ не заботится об этом. Если в курсе обучается более одного студента (в любое время) и на одном этапе он был представлен в пятницу днем, тогда он соответствует требованиям. Учащиеся не обязательно будут в классе вместе в одно и то же время — или, действительно, у вас могут быть студенты, которые даже не посещали занятия в пятницу днем (например, они проходили курс в другом потоке / временном интервале).

Хотя мой ответ может дать первоначальный буквальный ответ на вопрос, более содержательная интерпретация вопроса («в каких классах в пятницу днем одновременно учится более 1 ученика?»), Вероятно, это то, что они спрашивают.

И поскольку это похоже на домашнее задание — я предлагаю, чтобы следующим шагом было изменение приведенного выше. Причина, по которой я выбрал подзапросы для выполнения фильтрации в приведенном выше ответе, заключается в том, что мне легче изменить then для другой фильтрации.

PS Вот подсказка о том, как / что изменить: приведенный выше ответ выполняет всю свою работу вокруг таблицы «курс», например, Он находит студентов по курсу, временные интервалы по курсу и т. Д. Вместо этого вы можете сосредоточиться на таблице ‘section’, поскольку она предоставляет данные о курсах в определенное время.

Комментарии:

1. Это отличный и хорошо продуманный ответ, который проведет меня (шаг за шагом) через мыслительный процесс, лежащий в основе построения SQL-запроса. Спасибо, что нашли время для его написания. Это очень ценится.