首先,让我们处理您的特定问题。使用子查询时,必须注意其上下文。有两种上下文:表和标量。在表上下文中,子查询应返回一组行。在标量上下文中,它需要返回单个值(一行一列)。你怎么知道哪个是哪个?表上下文将由以下结构指示:
FROM (...)
JOIN (...)
WHERE ... IN(...)
标量上下文或多或少在其他任何地方。如果您将子查询的结果与单个值(如 where 子句中的列)进行比较,或者将结果用作 SELECT 字段列表中的计算列,则子查询处于标量上下文中。
在您的特定查询中,您将子查询的结果与 NULL 进行比较。由于 NULL 是单个值,因此我们讨论的是标量上下文。因此,子查询需要返回单个结果。你的不是,它可能正在发生,因为一个人所属的学校有很多。不管。我想我能猜出你打算做什么。您只想包括属于至少一所学校的人员。您可以像这样更有效地编写它:
WHERE EXISTS(SELECT * FROM School S WHERE P.stdNo = S.stdNo)
您可以将 替换*
为列或表达式。这并不重要,因为EXISTS()
测试是否返回任何行并且不对特定结果做任何事情。
但是,您有一个更大的问题,那就是您正在对 Person 和 Class 表进行笛卡尔积。我假设您实际上希望以某种方式将人们与课程相匹配。因为使用逗号运算符很容易意外地进行笛卡尔连接,所以我总是使用并推荐显式JOIN
运算符。如果你说INNER JOIN
(或其他类型)而不指定连接谓词,你会得到一个语法错误。所以你应该有这样的东西:
FROM Person P
JOIN Class C
ON <condition>
现在,对于您关于独立子查询与相关子查询的其他问题。一个独立的子查询是最简单的情况。这是一个子查询,它不引用查询中在其外部使用的任何表或列。相关子查询引用在其外部使用的表或列。您的子查询是相关的,因为它引用了P.stdNo
,它包含在子查询之外的查询中。相关子查询必须对其包含的上下文中的每一行进行逻辑执行。在您的情况下,WHERE 子句检查的每一行都会导致子查询的逻辑执行,使用来自该特定行的数据(在这种情况下,P.stdNo
)。出于显而易见的原因,独立子查询只需要在逻辑上执行一次。