SQL子查询完整指南

276 阅读5分钟

基础知识

子查询是一个嵌套在主查询的SELECT、FROM或WHERE子句中的查询。子查询被包裹在圆括号中,与主查询分开。

在下面的例子中,使用WHERE子句中的子查询选择所有年龄大于平均值的用户。

SELECT first_name,

子查询出现在WHERE子句中比较的右侧。这个子查询为平均数返回一个单一的值(标量值)。如果我们用子查询代替实际的平均值,查询的功能将完全相同。

SELECT first_name,

深入探究

为了更深入地了解子查询,我们可以看看子查询在SELECT、FROM和WHERE子句中的表现。这是一个很好的轨迹,因为这些用例中的每一个都有独特的问题。

所以让我们从头开始,从SELECT开始。

在SELECT中使用子查询

选择子句中的子查询必须只返回一条记录和一列,否则会发生错误。由于这个原因,select中的子查询经常被用来产生聚合值,而不把行分组。

考虑一下这个例子。

SELECT first_name,

像上面的例子中的子查询,其行为类似于聚合窗口函数。然而,与窗口函数不同,子查询不支持分区。

此外,SELECT子句中的子查询可以访问外部查询中的表列。当一个子查询引用来自外部查询表的列时,它被称为相关子查询。下面是一个在SELECT子句中的相关子查询的例子。

SELECT first_name,

在一个相关的子查询中,查询被逐行执行。SQL引擎先执行外部查询,然后再执行内部查询。这种执行顺序允许内部查询引用外部查询的列值。

当一个内部查询不引用外部查询的列时(换句话说,当它不是一个相关的子查询时),该查询不会被逐行执行。相反,SQL引擎会先执行内部查询,然后再执行外部查询。

*注意,如果在上面的例子中,verified_users包含重复的user_ids,查询将会失败。

在FROM中使用子查询

子查询可以用在FROM子句中,作为查询选择的主要结果集或作为连接到标准表的结果集。

让我们看看第一种情况的一个简单版本。

SELECT first_name,

注意在这个例子中,子查询被赋予了一个别名(kansas)。这是因为所有FROM子句中的子查询必须有一个别名。

下面是一个在连接中使用子查询的例子。这里,同样,子查询必须有一个别名。

SELECT first_name,

在WHERE中使用子查询

本节介绍了如何在WHERE子句中使用子查询。这些查询有两种类型:单行和多行。

单行子查询

在本文开头的基本例子中,我们在WHERE子句中使用了一个子查询,返回一个单一的值。

SELECT first_name,

这里是一个更复杂的例子,子查询本身是一个复杂的查询,用来确定一个员工最近的奖金支付情况,然后选择所有奖金支付较高的情况。

SELECT user_id,

这个例子表明,子查询可以和普通查询一样复杂和强大(并且包括自己的子查询!)。当你需要根据复杂查询返回的单一数值 来过滤数据时,子查询通常是首选方法。

此外,这被称为单行子查询。

单行子查询,当相互关联时,可以近似于内联。例如,如果我们有一个包含所有用户的用户表和一个只包含电子邮件被验证的用户的verified_users表,下面将模拟它们之间的内联。

SELECT first_name,

*注意,触发相关性的原因是内部查询引用了外部查询的列。

这里是另一个相关的单行子查询的例子。

SELECT first_name,

这个查询选择了一个年龄等于其所在州的最小年龄的用户列表。

*请注意,这个查询需要有别名才能执行。

多行子查询

在WHERE子句中使用的返回多行的子查询被称为多行子查询。你必须将多行子查询与一个集合比较运算符(IN, ALL, ANY)一起使用。此外,与单行子查询一样,多行子查询必须只返回一列。

如果你对这些集合运算符不熟悉,重要的是要记住每个运算符都是用来确定查询的输出中是否包括某一行。

使用IN运算符

IN运算符确定一个值是否存在于一个列值的列表中。在下面的例子中,我们返回一个所有用户的列表,这些用户的年龄出现在所有住在俄亥俄州的用户的年龄列表中。

SELECT first_name,

使用ALL操作符

ALL操作符决定了一个单一的行值和一个结果集的每一个行值之间的比较是否是一致的。如果比较一致为真,那么与比较的左手边相关的行就会被包括在内。

在下面的例子中,我们返回一个年龄大于每个住在堪萨斯州的用户的年龄的用户列表。

SELECT first_name,

使用ANY操作符

ANY操作符决定了一个单一的行值和一个结果集的每一个行值之间的比较是否至少有一次是真的。如果比较至少有一次为真,那么与比较的左手边相关的行就会被包括在内。

在下面的例子中,我们返回一个年龄大于各州用户最大年龄的用户列表。

SELECT first_name,

回顾我们所学的内容

子查询是SQL中比较容易混淆的主题之一。如果你感到迷茫,请记住这些要点。

  1. 所有的子查询都必须用圆括号括起来 🎯
  2. 在SELECT子句中使用的子查询必须返回一个单一的值 🎯
  3. 在FROM子句中使用的子查询必须有一个别名 🎯
  4. 如果WHERE子句中的子查询返回多条记录,它必须使用集合比较运算符(IN、ALL、ANY) 🎯
  5. 引用外部查询列的子查询是相关的 🎯