有时,你可能希望将查询的结果用作另一个查询中的字段,或用作查询字段的条件。 例如,假设你想要查看每个产品的订单间隔。 若要创建显示此间隔的查询,需要将每个订单日期与该产品的其他订单日期进行比较。 比较这些订单日期还需要查询。 可以使用 子查询 将此查询嵌套在 main 查询中。
可以在 表达式 或 SQL 视图 结构化查询语言 (SQL) 语句中编写子查询。
本文内容
将查询的结果用作另一个查询中的字段
可以使用子查询作为字段别名。 如果要将子查询结果用作main查询中的字段,请使用子查询作为字段别名。
注意: 用作字段别名的子查询不能返回多个字段。
可以使用子查询字段别名来显示依赖于当前行中的其他值的值,如果不使用子查询,这是不可能的。
例如,让我们返回到想要查看每个产品的订单间隔的示例。 若要确定此间隔,需要将每个订单日期与该产品的其他订单日期进行比较。 可以使用 Northwind 数据库模板创建显示此信息的查询。
-
在“文件”选项卡上,单击“新建”。
-
在 “可用模板”下,单击“ 示例模板”。
-
单击“ Northwind”,然后单击“ 创建”。
-
按照“罗斯文贸易”页(在“启动屏幕”对象选项卡上)上的说明打开数据库,然后关闭“登录对话框”窗口。
-
在“创建”选项卡上的“查询”组中,单击“查询设计”。
-
单击“ 查询 ”选项卡,然后双击“ 产品订单”。
-
双击“ 产品 ID ”字段和“ 订单日期 ”字段,将其添加到查询设计网格。
-
在网格的“产品 ID”列的“排序”行中,选择“升序”。
-
在网格的“订单日期”列的“排序”行中,选择“降序”。
-
在网格的第三列中,右键单击“ 字段” 行,然后单击快捷菜单上的“ 缩放 ”。
-
在“ 缩放 ”对话框中,键入或粘贴以下表达式:
Prior Date: (SELECT MAX([Order Date])
FROM [Product Orders] AS [Old Orders]
WHERE [Old Orders].[Order Date] < [Product Orders].[Order Date]
AND [Old Orders].[Product ID] = [Product Orders].[Product ID])此表达式是子查询。 对于每一行,子查询选择最近的订单日期,该日期小于已与行关联的订单日期。 请注意如何使用 AS 关键字 (keyword) 创建表别名,以便可以将子查询中的值与main查询当前行中的值进行比较。
-
在网格的第四列中的 “字段” 行中,键入以下表达式:
Interval: [Order Date]-[Prior Date]
此表达式使用我们通过使用子查询定义的上一个日期的值,计算该产品的每个订单日期与上一个订单日期之间的间隔。
-
在“设计”选项卡上的“结果”组中,单击“运行”。
-
查询运行并显示产品名称、订单日期、先前订单日期以及订单日期之间的间隔的列表。 结果先按产品 ID (按) 升序排序,然后按订单日期 (降序) 排序。
-
注意: 由于产品 ID 是查阅字段,因此默认情况下,Access 显示查找值 (在这种情况下,产品名称) ,而不是实际的产品 ID。 虽然这会更改显示的值,但它不会更改排序顺序。
-
-
关闭 Northwind 数据库。
使用子查询作为查询字段的条件
可以使用子查询作为字段条件。 如果要使用子查询的结果来限制字段显示的值,请使用子查询作为字段条件。
例如,假设你想要查看 不是销售代表 的员工处理的订单列表。 若要生成此列表,需要将每个订单的员工 ID 与非销售代表的员工的员工 ID 列表进行比较。 若要创建此列表并将其用作字段条件,请使用子查询,如以下过程所示:
-
打开 Northwind.accdb 并启用其内容。
-
关闭登录窗体。
-
在“创建”选项卡上的“其他”组中,单击“查询设计”。
-
在“ 表 ”选项卡上,双击“ 订单 和 员工”。
-
在“订单”表中,双击“ 员工 ID ”字段、“ 订单 ID” 字段和“ 订单日期 ”字段,将其添加到查询设计网格。 在“雇员”表中,双击“ 职务” 字段,将其添加到设计网格。
-
右键单击“员工 ID”列的“ 条件” 行,然后单击快捷菜单上的“ 缩放 ”。
-
在“ 缩放 ”框中,键入或粘贴以下表达式:
IN (SELECT [ID] FROM [Employees]
WHERE [Job Title]<>'Sales Representative')这是子查询。 它选择员工没有销售代表职务的所有员工 ID,并将该结果集提供给main查询。 然后,main查询检查“订单”表中的员工 ID 是否在结果集中。
-
在“设计”选项卡上的“结果”组中,单击“运行”。
查询运行,查询结果显示由非销售代表的员工处理的订单列表。
可用于子查询的常见 SQL 关键字
有几个 SQL 关键字可用于子查询:
注意: 此列表并不详尽。 可以在子查询中使用任何有效的 SQL 关键字 (keyword) ,但数据定义关键字除外。
-
所有 在 WHERE 子句中使用 ALL 可检索与子查询返回的每一行进行比较时满足条件的行。
例如,假设你正在分析一所大学的学生数据。 学生必须保持最低 GPA,该最低 GPA 因专业而异。 专业及其最低 GPA 存储在名为 Majors 的表中,相关的学生信息存储在名为 Student_Records 的表中。
若要查看 (专业及其最低 GPA) 每个具有该专业的学生超过最低 GPA 的列表,可以使用以下查询:
SELECT [Major], [Min_GPA]
FROM [Majors]
WHERE [Min_GPA] < ALL
(SELECT [GPA] FROM [Student_Records]
WHERE [Student_Records].[Major]=[Majors].[Major]); -
任何 在 WHERE 子句中使用 ANY 可检索与子查询返回的至少一行相比满足条件的行。
例如,假设你正在分析一所大学的学生数据。 学生必须保持最低 GPA,该最低 GPA 因专业而异。 专业及其最低 GPA 存储在名为 Majors 的表中,相关的学生信息存储在名为 Student_Records 的表中。
若要查看 (专业及其最低 GPA) 的列表,该专业的任何学生都不符合最低 GPA,可以使用以下查询:
SELECT [Major], [Min_GPA]
FROM [Majors]
WHERE [Min_GPA] > ANY
(SELECT [GPA] FROM [Student_Records]
WHERE [Student_Records].[Major]=[Majors].[Major]);注意: 还可以将 SOME 关键字 (keyword) 用于同一目的;SOME 关键字 (keyword) 与 ANY 同义。
-
EXISTS 在 WHERE 子句中使用 EXISTS 指示子查询应至少返回一行。 还可以将 EXISTS 开头与 NOT 一起指示子查询不应返回任何行。
例如,以下查询返回至少在一个现有订单中找到的产品列表:
SELECT *
FROM [Products]
WHERE EXISTS
(SELECT * FROM [Order Details]
WHERE [Order Details].[Product ID]=[Products].[ID]);使用 NOT EXISTS,查询返回至少一个现有订单中未找到的产品列表:
SELECT *
FROM [Products]
WHERE NOT EXISTS
(SELECT * FROM [Order Details]
WHERE [Order Details].[Product ID]=[Products].[ID]); -
IN 在 WHERE 子句中使用 IN 验证main查询当前行中的值是否是子查询返回的集的一部分。 还可以将 IN 作为 NOT 的开头,以验证main查询当前行中的值是否不是子查询返回的集的一部分。
例如,以下查询返回 (订单列表,其中包含由非销售代表的员工处理的订单日期) :
SELECT [Order ID], [Order Date]
FROM [Orders]
WHERE [Employee ID] IN
(SELECT [ID] FROM [Employees]
WHERE [Job Title]<>'Sales Representative');通过使用 NOT IN,可以按以下方式编写相同的查询:
SELECT [Order ID], [Order Date]
FROM [Orders]
WHERE [Employee ID] NOT IN
(SELECT [ID] FROM [Employees]
WHERE [Job Title]='Sales Representative');