Использование SQL не существует - PullRequest
1 голос
/ 18 марта 2019

Я пытаюсь обернуть голову, чтобы понять работу подразделения, используя НЕ СУЩЕСТВУЕТ. Я знаю, как написать SQL-запрос, используя не Exist. Но как-то мне не хватает, как происходит оценка для таких запросов. Будем весьма благодарны за любые объяснения и помощь.

Мой запрос: укажите имена студентов, которые зачислены на все курсы.

student стол

SID SName
S1 Amy
S2 Tracy

course таблица

CID coursename
C1  computer
C2  Biology

enrolled таблица. Ключ SID и CID

SID  CID
S1   C1
S1   C2
S2   C1

Мой SQL-запрос выглядит так:

SELECT s.SName
FROM student s
WHERE NOT EXISTS
(SELECT CID from course c
WHERE NOT EXISTS
(SELECT S.SID 
FROM enrolled E
WHERE S.SID=E.SID AND
C.CID=E.CID));

Насколько я понимаю:

для S1: внутренний запрос будет получать - Сначала C1 и проверьте, зарегистрирован ли S1 в C1 или нет. В нашем случае. он. Это вернет ложь - тогда он проверит C2 и снова будет ложным.

это так? я в замешательстве сейчас.

Ответы [ 2 ]

1 голос
/ 18 марта 2019

SQL выглядит нормально.

Чтобы ответить на ваш актуальный вопрос: «Но почему-то мне не хватает того, как происходит оценка для таких запросов».

Что происходит концептуально заключается в том, что самый внешний выбор [FROM STUDENT AS S] охватывает всех учащихся по одному, каждый раз сохраняя значения атрибута из текущей строки в контексте для дальнейшего использования.

Тогда самое внешнее, ГДЕ НЕ СУЩЕСТВУЕТ, сканирует все курсы [ВЫБРАТЬ ИЗ КУРСА] один за другим, в результате чего значения атрибутов из «текущей» строки снова сохраняются в контексте для дальнейшей ссылки [так что теперь у нас есть оба «текущий» ряд студентов, а также «текущий» ряд курсов].

Тогда самый внутренний ГДЕ НЕ СУЩЕСТВУЕТ, проверяя, есть ли зачисление для ученика из контекста и курса из контекста. Если нет, то есть курс, на который студент не зачислен, так что конкретный студент не следует всем курсам.

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

EDIT

В более формальной логической терминологии:

Запрос запрашивает

{СТУДЕНТ | ДЛЯ ВСЕХ КУРСОВ: ЗАПИСАНО (SID, CID)}

в ENROLLED (), SID привязан к ограниченному набору STUDENT, а CID привязан к теме FORALL.

(Возможно, в качестве упражнения проверьте, насколько это почти буквально постановка задачи.)

Отрицанием FORALL, это то же самое, что и

{СТУДЕНТ | КУРС НЕ СУЩЕСТВУЕТ: НЕ ЗАПИСАН (SID, CID)}

И условие NOT ENROLLED (), являющееся истинным, отмечается отсутствием (то есть несуществованием) соответствующей строки SID, CID. Опять же, в качестве упражнения, проверьте, насколько это практически буквально решение SQL.

0 голосов
/ 18 марта 2019

Возможно, другой подход легче понять.

Это ваш пример для SQLite:

PRAGMA foreign_keys = ON;

create table student (
  SID text primary key,
  SName text
);

insert into student (SID, SName) values ('S1', 'Amy');
insert into student (SID, SName) values ('S2', 'Tracy');

create table course (
  CID text primary key,
  coursename text
);

insert into course (CID, coursename) values ('C1', 'computer');
insert into course (CID, coursename) values ('C2', 'Biology');

create table enrolled (
  SID text references student (SID),
  CID text references course (CID),
  primary key (SID, CID)
);

insert into enrolled (SID, CID) values ('S1', 'C1');
insert into enrolled (SID, CID) values ('S1', 'C2');
insert into enrolled (SID, CID) values ('S2', 'C1');

Вы хотите тех студентов, которые не пропустили курс.SID и CID являются первичными ключами enrolled.Это означает, что студент не может пройти один и тот же курс дважды.А это значит, что вы просто должны считать курсы.Если количество курсов на одного учащегося совпадает с количеством курсов на всех, студент имеет все курсы.

Это число всех курсов:

select count(*) from course;

И этоколичество курсов каждого студента:

select count(SName) n, SName from student s
left join enrolled e on s.SID = e.SID
group by SName;

И вот список студентов, которых вы ищете:

select SName from (
  select count(SName) n, SName from student s
  left join enrolled e on s.SID = e.SID
  group by SName)
where n = (select count(*) from course);
...