我有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和内部选择,但我不知道如何将它与第二部分连接以及如何将NOT IN转换为关系代数。
答案 0 :(得分:1)
如果NOT IN (subquery)
中的子查询为`studentid`返回NULL值,我们不依赖于我们得到的行为......
(如果子查询返回NULL,则对于任何行,NOT IN比较永远不会计算为TRUE,因此外部查询不会返回任何行。)
可能有某种保证`studentid`永远不会为NULL,就像它被定义为NOT NULL或它是PRIMARY KEY ......但我们没有看到。并且该子查询中没有studentid IS NOT NULL
条件,因此我们必须预测子查询返回NULL时将发生的行为。
如果我们对保留这种行为不感兴趣,
然后NOT IN (subquery)
可以表示为反连接模式。
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
反连接模式看起来像一个外连接(从一侧返回所有行以及从另一侧返回匹配的行),以及WHERE子句中排除所有匹配行的条件。
这是有效的,因为对于找到的任何匹配行,at.studentid
保证为非NULL。对于来自need
但aj
中没有匹配行的任何行,这些行将为aj
中的列设置NULL值。 (这就是外连接基本上做的...发明一行NULL值作为连接操作的占位符匹配行。)
对于WHERE子句中的条件测试,我们需要做的就是测试aj
中保证为非NULL的一列中的NULL值。如果我们知道那是什么,我们可以参考表格的PRIMARY KEY。我们可以使用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