tencent cloud

TDSQL Boundless

产品动态
产品简介
产品概述
应用场景
产品架构
实例类型
兼容性说明
使用规范建议
自研内核
内核概述
内核版本更新动态
功能类特性
性能类特性
产品计费
计费概述
购买方式
价格详情
续费说明
欠费说明
退费说明
快速入门
创建实例
连接实例
用户指南
数据迁移
数据同步/订阅
实例管理
参数配置
账号管理
安全组
备份与恢复
数据库审计
标签管理
实践教程
Online DDL 的技术演进与使用实践
锁机制解析与问题排查实践
数据智能调度及相关性能优化实践
TDSQL Boundless 选型指南与实践教程
开发指南
开发指南(MySQL 兼容模式)
开发指南(HBase 兼容模式)
性能调优
性能调优概述
SQL 调优
DDL 调优
性能白皮书
性能概述
TPC-C 测试
Sysbench 测试
API 文档
History
Introduction
API Category
Making API Requests
Instance APIs
Security Group APIs
Task APIs
Backup APIs
Rollback APIs
Parameter APIs
Database APIs
Data Types
Error Codes
通用参考
系统原理
SQL 参考
数据库参数说明
TPC-H 基准测试数据模型参考
错误码信息
安全与合规
常见问题
服务协议
服务等级协议
服务条款
隐私政策
数据处理和安全协议
联系我们
词汇表

子查询

PDF
聚焦模式
字号
最后更新时间: 2026-03-26 14:56:38
本文档介绍如何在 TDSQL Boundless 数据库中使用子查询。子查询是嵌套在另一个查询内部的 SQL 查询,允许你在一条语句中使用另一个查询的结果。

子查询的分类

在 TDSQL Boundless 中,子查询通常有以下几种形式:

标量子查询

标量子查询返回单行单列的值,可以出现在 SELECT 列表、WHERE 条件等任何需要单个值的位置。其关键特征是子查询的结果等价于一个常量值。
SELECT
c_name,
c_acctbal,
(SELECT AVG(c_acctbal) FROM customer) AS avg_balance
FROM customer
LIMIT 5;

派生表

派生表是放在 FROM 子句中的子查询,作为一个临时表参与后续查询。其关键特征是子查询必须用括号包裹并指定别名。
SELECT seg.c_mktsegment, seg.cnt
FROM (
SELECT c_mktsegment, COUNT(*) AS cnt
FROM customer
GROUP BY c_mktsegment
) seg
ORDER BY seg.cnt DESC;

存在性测试

通过 EXISTSNOT EXISTSINNOT IN 等关键字判断子查询是否返回数据,结果是布尔值。其关键特征是不关心子查询返回的具体值,只关心是否有行存在。
-- EXISTS:判断是否存在匹配行
SELECT c_name FROM customer c
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.o_custkey = c.c_custkey
);

-- IN:判断值是否在结果集中
SELECT c_name FROM customer
WHERE c_nationkey IN (SELECT n_nationkey FROM nation WHERE n_name = 'CHINA');

集合比较

使用 ANYALLSOME 关键字将一个值与子查询返回的结果集进行比较。其关键特征是比较运算符(=>< 等)与 ANY/ALL 组合使用。
-- = ANY 等价于 IN
SELECT c_name, c_acctbal FROM customer
WHERE c_acctbal > ANY (
SELECT o_totalprice FROM orders WHERE o_orderstatus = 'F'
);

-- > ALL:大于子查询返回的所有值
SELECT c_name, c_acctbal FROM customer
WHERE c_acctbal > ALL (
SELECT AVG(c_acctbal) FROM customer GROUP BY c_mktsegment
);

作为比较运算符操作数

子查询直接作为比较运算符(><=>=<=<>)的一侧操作数。其关键特征是子查询必须返回单行单列(即标量),与标量子查询的区别在于它出现在 WHERE/HAVING 的比较条件中。
SELECT o_orderkey, o_totalprice
FROM orders
WHERE o_totalprice > (
SELECT AVG(o_totalprice) FROM orders
);

子查询的相关性

根据子查询是否引用了外层查询的列,可分为非关联子查询关联子查询两类。

非关联子查询

非关联子查询不引用外层查询的任何列,其结果独立于外层查询。TDSQL Boundless 会先执行内层子查询,将结果作为常量代入外层查询。
查询账户余额高于所有客户平均余额的客户:
SELECT c_custkey, c_name, c_acctbal
FROM customer
WHERE c_acctbal > (
SELECT AVG(c_acctbal) FROM customer
);
TDSQL Boundless 在处理该查询时,会先执行内层子查询:
SELECT AVG(c_acctbal) FROM customer;
假设计算结果为 4990.51,则外层查询等价于:
SELECT c_custkey, c_name, c_acctbal
FROM customer
WHERE c_acctbal > 4990.51;
使用 IN 子查询查找有过订单的客户:
SELECT c_custkey, c_name, c_mktsegment
FROM customer
WHERE c_custkey IN (
SELECT DISTINCT o_custkey FROM orders
WHERE o_orderdate >= '1995-01-01'
);
内层子查询独立执行,返回一组 o_custkey 值,外层查询在这组值中进行匹配。

关联子查询

关联子查询引用了外层查询的列,因此内层查询的结果依赖于外层查询当前正在处理的行。从逻辑上看,关联子查询需要对外层的每一行都重新执行一次内层查询。
查询每个客户中金额最大的订单:
SELECT o_orderkey, o_custkey, o_totalprice, o_orderdate
FROM orders o1
WHERE o_totalprice = (
SELECT MAX(o2.o_totalprice)
FROM orders o2
WHERE o2.o_custkey = o1.o_custkey
);
内层子查询引用了外层的 o1.o_custkey,对于外层每一行,子查询计算该客户的最大订单金额,然后只保留金额等于最大值的行。
查询账户余额高于同市场细分客户平均余额的客户:
SELECT c1.c_custkey, c1.c_name, c1.c_mktsegment, c1.c_acctbal
FROM customer c1
WHERE c1.c_acctbal > (
SELECT AVG(c2.c_acctbal)
FROM customer c2
WHERE c2.c_mktsegment = c1.c_mktsegment
);
TDSQL Boundless 优化器会尝试对关联子查询进行去关联(Unnesting)优化,将其改写为等价的 JOIN 查询以提升性能。例如上述查询可能被改写为:
SELECT c1.c_custkey, c1.c_name, c1.c_mktsegment, c1.c_acctbal
FROM customer c1
INNER JOIN (
SELECT c_mktsegment, AVG(c_acctbal) AS avg_acctbal
FROM customer
GROUP BY c_mktsegment
) c2 ON c1.c_mktsegment = c2.c_mktsegment
WHERE c1.c_acctbal > c2.avg_acctbal;
改写后的查询只需对 customer 表扫描两次(一次聚合、一次连接),而不是对每个客户都执行一次子查询,性能显著提升。

常见子查询场景

EXISTS 子查询

EXISTS 用于判断子查询是否返回了至少一行数据,常用于存在性检查。
查询有过高金额订单(金额 > 300000)的客户:
SELECT c.c_custkey, c.c_name, c.c_acctbal
FROM customer c
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.o_custkey = c.c_custkey
AND o.o_totalprice > 300000
);
查询没有下过订单的客户(NOT EXISTS):
SELECT c.c_custkey, c.c_name, c.c_phone
FROM customer c
WHERE NOT EXISTS (
SELECT 1 FROM orders o
WHERE o.o_custkey = c.c_custkey
);
NOT EXISTS 在语义上等价于 LEFT JOIN ... WHERE ... IS NULL,但在某些场景下两者的执行效率不同,可通过 EXPLAIN 进行比较。

IN 子查询

IN 用于判断某个值是否在子查询返回的结果集中。
查询来自 ASIA 区域国家的客户:
SELECT c_custkey, c_name, c_nationkey
FROM customer
WHERE c_nationkey IN (
SELECT n_nationkey FROM nation
WHERE n_regionkey IN (
SELECT r_regionkey FROM region
WHERE r_name = 'ASIA'
)
);
IN 与 EXISTS 的选择:当子查询返回的结果集较小时,INEXISTS 性能差异不大;当外层表较小而子查询结果集较大时,EXISTS 通常更高效。

标量子查询

标量子查询返回单个值,可以出现在 SELECT 列表、WHERE 条件等位置。
在 SELECT 列表中使用标量子查询 — 查询每个订单及其客户名称:
SELECT
o_orderkey,
o_totalprice,
o_orderdate,
(SELECT c_name FROM customer WHERE c_custkey = o_custkey) AS customer_name
FROM orders
WHERE o_orderdate = '1995-03-15';
SELECT 列表中的标量子查询在逻辑上会对每一行执行一次,当外层行数较多时建议改写为 JOIN:
SELECT
o.o_orderkey,
o.o_totalprice,
o.o_orderdate,
c.c_name AS customer_name
FROM orders o
INNER JOIN customer c ON o.o_custkey = c.c_custkey
WHERE o.o_orderdate = '1995-03-15';

派生表(FROM 子句中的子查询)

子查询放在 FROM 子句中作为临时表(派生表)使用。
查询每个市场细分中账户余额最高的客户:
SELECT c.c_custkey, c.c_name, c.c_mktsegment, c.c_acctbal
FROM customer c
INNER JOIN (
SELECT c_mktsegment, MAX(c_acctbal) AS max_acctbal
FROM customer
GROUP BY c_mktsegment
) seg_max ON c.c_mktsegment = seg_max.c_mktsegment
AND c.c_acctbal = seg_max.max_acctbal;
统计各订单优先级的订单数量和平均金额,只保留数量超过 10000 的优先级:
SELECT *
FROM (
SELECT
o_orderpriority,
COUNT(*) AS order_count,
AVG(o_totalprice) AS avg_amount
FROM orders
GROUP BY o_orderpriority
) summary
WHERE order_count > 10000
ORDER BY order_count DESC;


帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈