2016-04-26 4 views
0

У меня есть SQL заявление:Перевести SQL заявление реляционной алгебры

SELECT need.studentid, need.firstname, need.lastname, need.courseid 
FROM 
    (SELECT student.studentid, student.firstname, student.lastname, enrollment.courseid 
     FROM prereq LEFT JOIN enrollment ON prereq.courseid = enrollment.courseid LEFT JOIN student ON enrollment.studentid = student.studentid) AS need 

WHERE need.studentid NOT IN (SELECT studentid 
FROM enrollment 
WHERE NOT(grade LIKE '%F' OR grade IS NULL OR grade LIKE 'N')) 

Моя цель состоит в том, чтобы преобразовать это в реляционной алгебре. Мне удалось преобразовать Left Joins и inner select, но я не знаю, как соединить это со второй частью и как преобразовать NOT IN в реляционную алгебру.

+0

Перед тем, как преобразование в РА, так как 'NOT в' часть включает в себя таблицу, в которой уже имеются ссылки в объединение в первых скобках, вероятно, можно преобразовать выражение фильтра из' NOT IN (SELECT .. .' часть в состояние фильтра прямо на соединение. –

+0

Ну, не могли бы вы дать мне подсказку, как это сделать? –

ответ

1

Если мы не в зависимости от поведения, которое мы получили бы, если подзапрос в NOT IN (subquery) возвратит значение NULL для `studentid` ...

(Если подзапрос возвращает NULL, то НЕ Сравнение IN никогда не будет оцениваться до TRUE для любой строки, поэтому внешний запрос не будет возвращать никакие строки.)

Возможно, существует какая-то гарантия того, что `studentid` никогда не будет NULL, как и его определенные чтобы быть НЕ НАЙДЕННЫМ, или это ПЕРВИЧНЫЙ КЛЮЧ ... но мы этого не видим. И в этом подзапросе нет условия studentid IS NOT NULL, поэтому мы должны предвидеть поведение, которое произойдет, если подзапрос вернет NULL.

Если мы не заинтересованы в сохранении такого поведения,

то NOT IN (subquery) может быть выражено как antijoin узор.

SELECT need.studentid 
    , need.firstname 
    , need.lastname 
    , need.courseid 
    FROM (SELECT student.studentid 
       , student.firstname 
       , student.lastname 
       , enrollment.courseid 
      FROM prereq 
      LEFT 
      JOIN enrollment 
      ON prereq.courseid = enrollment.courseid 
      LEFT 
      JOIN student 
      ON enrollment.studentid = student.studentid 
     ) need 
    LEFT 
    JOIN enrollment aj 
    ON aj.studentid = need.studentid 
    AND NOT (aj.grade LIKE '%F' OR aj.grade IS NULL OR aj.grade LIKE 'N') 
WHERE aj.studentid IS NULL 

анти-присоединиться модель выглядит как внешнее соединение (вернуть все строки, с одной стороны, а также соответствующие строки из другого), и условие в ИНЕКЕ, что исключает все строки, которые имели матч.

Это работает, потому что гарантируется, что at.studentid не имеет значения NULL для любых найденных совпадающих строк. Для любой строки из need, у которой не было соответствующей строки в aj, эти строки будут иметь значение NULL для столбцов с aj. (Это то, что в основном заключается в внешнем соединении ... вставляет строку значений NULL, чтобы служить в качестве строки соответствия заполнителя для операции соединения.)

Для условного теста в предложении WHERE все, что нам нужно сделать, это проверить для значений NULL в одном из столбцов от aj, которые гарантированно будут не равными NULL. Если бы мы знали, что это такое, мы могли бы обратиться к ПЕРВИЧНОМУ КЛЮЧУ таблицы. Мы можем использовать столбец studentid, потому что любая строка, которая удовлетворяет сопоставлению равенства в условии соединения, гарантируется, что она не является NULL.)

SQL-антияпон можно перевести в реляционную алгебру.

Эквивалентный результат может быть возвращен без встроенного представления.

SELECT student.studentid 
    , student.firstname 
    , student.lastname 
    , enrollment.courseid 
    FROM prereq 
    LEFT 
    JOIN enrollment 
    ON prereq.courseid = enrollment.courseid 
    LEFT 
    JOIN student 
    ON enrollment.studentid = student.studentid 
    LEFT 
    JOIN enrollment aj 
    ON aj.studentid = student.studentid 
    AND NOT (aj.grade LIKE '%F' OR aj.grade IS NULL OR aj.grade LIKE 'N') 
WHERE aj.studentid IS NULL