首页 > 解决方案 > 无法理解涉及跨不同表的不同列的 SQL 查询中的控制流

问题描述

我想改进我的 SQL,为此我需要了解 SQL 中的控制流。我了解基础知识,但这是一个这样的例子,我无法理解如何在不同查询(子查询)中的另一个表的 where 子句中使用一个表中的列?

是问题陈述。查询是:

SELECT
IF (Grade >= 8, Name, NULL),
Grade,
Marks
FROM
(SELECT
Name,
(SELECT Grade FROM Grades WHERE (Min_Mark <= Marks) AND (Marks <= Max_Mark)) AS Grade,
Marks
FROM Students) As MyStudents
ORDER BY Grade DESC, Name;

我的疑问是在子查询中:(SELECT Grade FROM Grades WHERE (Min_Mark <= Marks) AND (Marks <= Max_Mark)),为什么可以使用“标记”?

标签: mysqlsql

解决方案


您所拥有的是所谓的相关子查询,MySQL(和许多其他 RDBMS)允许来自外部查询的字段在子查询中引用一个“层”深。一种查看方式是子查询可以访问它们所包含的查询范围,但不能访问更远的范围。

在多表查询中,最好用它们来自的表(或表的别名)来限定所有字段名称,以使查询更易于阅读;这在这种情况下尤其重要,因为在您的查询的当前形式中,它甚至具有相关性并不明显。

在来自外部查询的小数据集上,特别是当子查询中的数据计算成本相对较高时,相关子查询可以更快;但是当来自外部查询的大量数据必须由相关子查询处理时,相关子查询可能会变得非常昂贵,因为相关子查询被重复处理(外部查询中的每一行一次)。

此外,必须注意外部查询的 SELECT 中的子查询。这样的子查询必须只返回一行。

作为一般规则,除非子查询大大减少连接的行数,否则连接几乎总是性能更好。

您的查询似乎不需要任何子查询:

SELECT IF(g.Grade >= 8, s.Name, NULL)
   , g.Grade
   , s.Marks
FROM Students AS s
LEFT JOIN Grades AS g ON s.Marks BETWEEN g.Min_Mark AND g.Max_Mark
ORDER BY g.Grade DESC, s.Name
;

推荐阅读