SQL 关系除法和AS别名的坑
参考资料: division.pdf
举例: 学生选修课表 Taken(Student,Course)和毕业必修课 Required(Course), 查询可以毕业的学生
整体思路
- 找出全体学生,总学生表
- 假设所有人都能毕业, 理想的选课表
- 拿理想选课表减去实际的选课表, 得到缺课表
- 缺课表里有名字的学生不能毕业, 找出他们(延毕表)
- 总学生表减去延毕表,得到能毕业学生表
参考资料中给出了详细的分步骤实现
mariadb 中临时表关键字是TEMPORARY
而不是TEMP
思考:
- 关系除法的意义?我认为是条件组的满足, 上面的例子中是选择所有的课
- 其他的实现方法?
选了所有必修课的学生可以毕业 → 必修课选修数目必须等于总数目 →groupby
我踩的坑
- 必须命名每个子查询,否则 mariadb 不伺候
- EXCEPT 运算对象必须明确列名称
下面是我没调通一句话实现::EXCEPT 后,问 gpt 的结果
-
问:
我希望完成一个 sql 关系除法的查询语句,但 mariadb 总是说我的语法有问题,你能帮忙看问题在哪里吗?应该怎么改呢?
SELECT Student FROM Taken EXCEPT SELECT Student FROM ( SELECT Student,Course FROM (SELECT DISTINCT Student FROM Taken), Required EXCEPT (SELECT * FROM Taken) );
-
回答:
根据你提供的 SQL 查询语句,以下是我发现的一些问题:
- 在第二个子查询中,你使用了一个未定义的表 Required。我猜测你可能想使用一个名为 Required 的表来做计算,但是在你的查询中没有定义这个表。
- 在第二个子查询中,你使用了一个 _ 号来选择所有的列。然而,在 EXCEPT 操作符中使用 _ 是无效的。你需要指定明确的列名,例如 SELECT Student, Course FROM Taken。
- 在第二个子查询中,你没有为子查询定义别名。你需要为这个子查询指定一个别名,例如:
SELECT Student FROM Taken EXCEPT SELECT Student FROM ( SELECT Student, Course FROM (SELECT DISTINCT Student FROM Taken) AS DistinctStudents, Required EXCEPT (SELECT Student, Course FROM Taken) AS TakenCourses ) AS StudentCourses;
在这个查询中,我为第一个子查询命名为 Taken,第二个子查询命名为 StudentCourses,并且为其中的每个子查询都指定了别名。
希望这能帮助你解决问题!
哈哈,这个一样跑不通,正相反,取消 TakenCourses 的那个别名,就能跑起来
SELECT Student FROM Taken
EXCEPT
SELECT Student FROM
(
SELECT Student, Course FROM
(SELECT DISTINCT Student FROM Taken) AS DistinctStudents, Required
EXCEPT
SELECT Student, Course FROM Taken
) AS StudentCourses;
到这份上,说真的,我也不知道什么时候用 AS 了,所以我又重复问了几次
-
-
问
修改后的这份代码同样报语法错误了,在 AS TakenCourses 处,我删掉了"AS TakenCourses",结果正常运行了。而与此同时,其他两个别名任意一个删除后,都会报语法错误。这是什么原因?我想知道 AS 语句到底是什么作用,什么情况下我需要使用它呢?
-
答
感谢你的反馈,我很高兴你的查询语句已经能正常运行了。
在 SQL 查询语句中,AS 是一个可选的关键字,用于为列、表或子查询指定别名。当你使用 AS 关键字时,你需要在关键字后面指定别名。如果你不使用 AS 关键字,则可以直接指定别名,例如:
SELECT Student, Course FROM Taken AS T;
和
SELECT Student, Course FROM Taken T;
这两个查询是等价的,它们都为 Taken 表指定了一个别名 T。
在你的修改后的查询语句中,如果你删除任何一个别名,查询就会报错。这是因为你的查询使用了嵌套的子查询,每个子查询都必须有一个别名以供上层查询使用。因此,每个子查询都必须使用 AS 关键字或直接指定别名。
如果你想了解更多关于 SQL 中的别名的信息,请参考相关的 SQL 教程或文档。希望这可以帮助回答你的问题!
-
-
-
问:
修改后的代码也报语法错误了,在"AS TakenCourses"附近。
我删除了"AS TakenCourses",结果查询正常了。
我突发奇想,在删除别名"AS TakenCourses"的同时,其他的别名可以删除吗?做了点尝试- 删除最后的"AS StudentCourses",报语法错误
- 删除"AS DistinctStudents",报语法错误
现在,我有点好奇,为什么"AS TakenCourses"删了就好了,而其他别名的像"AS DistinctStudents"不能删?sql 中别名的作用是什么?什么情况下必须使用别名呢?
-
答:
对于你的修改,我很高兴你已经成功地解决了语法错误。
在 SQL 中,别名是用于为表、子查询或计算列指定一个简短的名称的机制。别名可以使查询更易于阅读和理解,并且可以帮助在查询中使用表的自我关联或自我连接等高级查询操作。在大多数情况下,SQL 查询都必须为表、子查询或计算列指定一个别名,否则会报语法错误。
在你的修改中,第一个子查询中的别名 “Taken” 是必需的,因为在第二个子查询中使用了它。第二个子查询中的别名 “DistinctStudents” 也是必需的,因为它创建了一个表,用于保存从 “Taken” 表中选择的唯一的 “Student” 列。如果没有为这个子查询指定别名,就无法在下一级的子查询中引用这个表。
别名在 SQL 查询中的一个重要用途是解决歧义。当查询中包含多个表或多个列时,可能会出现多个名称相同的列或表。在这种情况下,必须为每个表或列指定一个别名,以避免歧义并明确指定要使用的表或列。
因此,SQL 中的别名是必需的,除非查询中只包含一个表或只包含一个列,并且没有任何歧义。
-
-
-
问:
修改后的代码也报语法错误了,在"AS TakenCourses"附近。
我在修改后代码的基础上做了些修改的尝试,结果很有趣。- 直接删除"AS TakenCourses",查询正常了
- 移动"AS TakenCourses"到左侧的括号内,查询也正常了
- 我突发奇想,在删除"AS TakenCourses"的同时,删除最后的"AS StudentCourses",报语法错误
- 在删除"AS TakenCourses"的同时,删除"AS DistinctStudents",报语法错误
当然,首先感谢您提供的思路,现在查询可以正常运行了。
现在,我有点好奇,为什么"AS TakenCourses"删了就好了,而其他别名的像"AS DistinctStudents"不能删?sql 中别名的作用是什么?什么情况下必须使用别名呢? -
答:
非常抱歉我之前提供的修改代码中还有问题,导致语法错误。下面是已经纠正了问题的代码:
SELECT Student FROM Taken EXCEPT SELECT Student FROM ( SELECT Student, Course FROM (SELECT DISTINCT Student FROM Taken) AS DistinctStudents, Required EXCEPT SELECT Student, Course FROM Taken ) AS StudentCourses;
现在回答你的问题:
- 别名的作用是让你可以为查询结果中的列或子查询结果中的表定义一个更具描述性的名称,以方便你编写 SQL 查询语句。它还允许你在一个查询中引用同一个表多次,因为你可以为每次引用定义一个不同的别名。
- 通常情况下,别名是可选的,但在某些情况下必须使用别名。例如,在一个查询中引用同一个表多次时,你必须为每次引用定义一个别名,否则会出现错误。此外,在使用子查询时,你通常需要为子查询定义一个别名,以便在主查询中引用子查询结果。
- 对于为什么删除 “AS TakenCourses” 可以正常运行,而删除其他别名却会导致语法错误,这是因为在这个查询中,“AS TakenCourses” 后面跟着的是主查询的结尾,因此在这个位置删除别名是可以的。然而,删除 “AS DistinctStudents” 或 “AS StudentCourses” 会破坏 SQL 查询语法的正确性,因为它们是必须的别名,没有别名会导致语法错误。
-