SQL必知会(二)-SQL查询篇(10)-使用子查询

第11课、使用子查询

(1)子查询

嵌套在其他查询中的查询。即在SELECT 语句里再内嵌一个SELECT 语句,后者便是子查询。

(2)利用子查询进行过滤

Order 表:客户ID、订单编号、订单日期

OrderItems 表:各订单的物品

Customers 表:顾客信息

【需求】:
总需求:检索订购物品 RGAN01 的所有顾客。 *
拆分需求:

(1)检索包含物品 RGAN01 的所有订单的编号。

(根据 prod_id 列值, 在 OrderItems 表中找出 order_num 列的列值)

(2)检索具有前一步骤列出的订单编号的所有顾客的 ID。

(根据 order_num 列值,在 Orders 表中找出 cust_id 列的列值)

(3)检索前一步骤返回的所有顾客 ID 的顾客信息。

(根据 cust_id 列值,在 Customers 表中找出其对应的行数据)

需求:(1)检索包含物品 RGAN01 的所有订单的编号。

sql 复制代码
SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGAN01';

-- 查询结果为:2007 和 2008 

输出结果:

复制代码
order_num
20007
20008

需求:(2)检索与订单 2007 和 2008 相关的顾客ID。

SQL 复制代码
SELECT cust_id
FROM Orders
WHERE order_num IN (20007,20008);

输出结果:

复制代码
cust_id
1000000004
1000000005

把需求(1)和需求(2)结合使用:

sql 复制代码
SELECT cust_id
FROM Orders
Where order_num IN(SELECT order_num
				  FROM OrderItems
				  WHERE prod_id = 'RGAN01');

--查询结果为:1000000004,1000000005

输出结果:

复制代码
cust_id
1000000004
1000000005

需求:(3)检索顾客 ID 的顾客信息。

sql 复制代码
SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN (1000000004,1000000005);

输出结果:

复制代码
cust_name	                                        cust_contact
Fun4All                                           	Denise L. Stephens                  
The Toy Store                                     	Kim Howard                                        

把需求(1)、(2)和(3)结合使用:

sql 复制代码
SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN(SELECT cust_id
				FROM Orders
				WHERE order_num IN (SELECT order_num
				FROM OrderItems
				WHERE prod_id = 'RGAN01'));

输出结果:

输出结果为 需求:(3 的结果。

c# 复制代码
//执行过程相似的伪代码:

//SELECT order_num FROM OrderItems WHERE prod_id = 'RGAN01'

            foreach (var items in OrderItems)
            {
                if(items.prod_id == "RGAN01")
                {
                    order_numArr.Add(items.order_num);
                    //由于 RGAN01 具有唯一性,找到后就跳出循环。
                    break;
                }
            }

//SELECT cust_id FROM Orders WHERE order_num IN (order_numArr);

            foreach (var items in Orders)
            {

                if (order_numArr.contain(items.order_num))
                {
                    cust_idArr.Add(items.cust_id);
                }
            }

//SELECT cust_name, cust_contact FROM Customers WHERE cust_id IN(cust_idArr)

            foreach (var items in Customers)
            {
                if (cust_idArr.contain(items.cust_id))
                {
                    onsole.WriteLine(customers.cust_name + customers.cust_contact)
                }
            }

(3)作为计算字段使用子查询

【需求】:
总需求:检索 Customers 表中每个顾客的订单总数。
拆分需求:

(1)从 Customers 表中检索顾客列表;

(2)对于检索出的每个顾客,统计其在 Orders 表中的订单数目。

需求:对顾客 1000000001 的订单进行计数。

sql 复制代码
SELECT COUNT(*) AS orders
FROM Orders
WHERE cust_id = 1000000001;

输出结果:

复制代码
orders
2

需求:对每个顾客的订单进行计数。

sql 复制代码
SELECT cust_name,
cust_state,
	(SELECT COUNT(*) 
	FROM Orders 
	WHERE Orders.cust_id = Customers.cust_id) AS orders 
	FROM Customers 
	ORDER BY cust_name;

输出结果:

复制代码
cust_name	cust_state	orders
Fun4All                                           	IN   	1
Fun4All                                           	AZ   	1
Kids Place                                        	OH   	0
The Toy Store                                     	IL   	1
Village Toys                                      	MI   	2

分析:

复制代码
总需求:检索 Customers 表中每个顾客的订单总数。
关键字:订单总数,每个顾客
排除使用 GROUP BY,GROUP BY 只对一张表里的行数据进行分组。此处用了两张表 Customers 和 Orders。
(1)检索每个顾客
SELECT cust_name FROM Customers;
(2)某个顾客的订单总数
SELECT COUNT(*)  FROM Orders WHERE cust_id = Customers.cust_id
(3)检索每个顾客的订单总数,要区分哪一个顾客,对应订单总数多少?
因此,(1)是主要查询,(2)是(1)的子查询。由于查询 cust_name 时,再分组输出其对应的订单总数,所以必须放在 SELECT 语句后作为列输出。

总结

子查询的单列

子查询只能返回某一个列,不能是多个列。所以子查询 SELECT 语句只能查询单个列。

比如错误写法:

sql 复制代码
SELECT 
(
SELECT COUNT(*) as Counts FROM Orders
group by cust_id --由于是分组,会返回多个值
)
FROM Customers ;
-- 错误,SELECT 一次返回的列值,不能是多个值。

子查询使用的列

复制代码
SELECT 列1,
	(SELECT COUNT(*) 
	FROM 表1 
	WHERE 某列[或表1.某列] = 表2.某列
	FROM 表2; 
相关推荐
CodeCraft Studio16 分钟前
文档开发组件Aspose 25.12全新发布:多模块更新,继续强化文档、图像与演示处理能力
前端·.net·ppt·aspose·文档转换·word文档开发·文档开发api
DBA小马哥33 分钟前
Oracle迁移实战:如何轻松跨越异构数据库的学习与技术壁垒
数据库·学习·oracle·信创·国产化平替
暮乘白帝过重山1 小时前
ArkTS ForEach 参数解析:组件与键值生成器
开发语言·数据库
PPPPickup1 小时前
easychat项目复盘---获取联系人列表,联系人详细,删除拉黑联系人
java·前端·javascript
老前端的功夫1 小时前
前端高可靠架构:医疗级Web应用的实时通信设计与实践
前端·javascript·vue.js·ubuntu·架构·前端框架
一条咸鱼¥¥¥1 小时前
【运维经验】使用QQ邮箱SMTP服务器设置ssms计划任务完成时邮件发送
运维·服务器·经验分享·sql·sqlserver
菜鸟plus+1 小时前
N+1查询
java·服务器·数据库
前端大卫1 小时前
【重磅福利】学生认证可免费领取 Gemini 3 Pro 一年
前端·人工智能
子夜江寒1 小时前
MySQL 表创建与数据导入导出
数据库·mysql
孜燃2 小时前
Flutter APP跳转Flutter APP 携带参数
前端·flutter