关联子查询
SELECT
cust_id,(SELECT SUM(quantity * item_price)
FROM OrderItems
WHERE OrderItems.order_num = Orders.order_num) AS total_orderedFROM Orders
ORDER BY total_ordered DESC;
这个查询之所以能正常工作而不会因为返回多行而报错,是因为它使用了关联子查询(Correlated Subquery),而且这个子查询被设计为返回单个值。
关键原因分析:
1. 关联子查询的特性
(SELECT SUM(quantity * item_price)FROM OrderItemsWHERE OrderItems.order_num = Orders.order_num) -- 这里关联外部查询
- 这个子查询为外部查询的每一行执行一次
- 每次执行时,它使用当前行的
Orders.order_num
作为过滤条件
2. 聚合函数保证返回单值
SELECT SUM(quantity * item_price) -- SUM保证返回单个值
FROM OrderItems
WHERE OrderItems.order_num = Orders.order_num -- 针对特定订单
SUM()
是一个聚合函数,它总是返回单个值- 即使匹配到多行数据,
SUM()
也会将它们聚合成一个总数
3. 执行过程分解
假设数据如下:
Orders表:
order_num | cust_id
----------|--------
1 | A
2 | BOrderItems表:
order_num | quantity | item_price
----------|----------|-----------
1 | 2 | 10
1 | 1 | 20
2 | 3 | 15
执行过程:
-
取Orders第一行:
order_num = 1, cust_id = A
- 子查询:
SUM(...) WHERE order_num = 1
→(2*10 + 1*20) = 40
- 返回:
(A, 40)
- 子查询:
-
取Orders第二行:
order_num = 2, cust_id = B
- 子查询:
SUM(...) WHERE order_num = 2
→(3*15) = 45
- 返回:
(B, 45)
- 子查询:
4. 与返回多行的子查询对比
会报错的例子:
SELECT cust_id,(SELECT quantity * item_price -- 没有SUM聚合FROM OrderItemsWHERE OrderItems.order_num = Orders.order_num) AS item_total
FROM Orders
这个会报错,因为对于每个订单,可能匹配多个OrderItems行。
为什么这是安全的?
- ✅ 一对一关系:外部查询每行对应子查询的一个结果
- ✅ 标量值:子查询使用
SUM()
确保返回单个值 - ✅ 关联条件:
WHERE OrderItems.order_num = Orders.order_num
确保正确的数据关联
性能考虑
虽然这个查询语法正确,但在性能上可能不如JOIN方式高效,因为它需要为Orders表的每一行执行一次子查询。对于大数据集,建议使用JOIN方式:
SELECT o.cust_id, SUM(oi.quantity * oi.item_price) as total_ordered
FROM Orders o
JOIN OrderItems oi ON o.order_num = oi.order_num
GROUP BY o.cust_id
ORDER BY total_ordered DESC;
总结: 这个子查询能正常工作是因为它被设计为关联子查询+聚合函数,确保为外部查询的每一行返回且只返回一个值。