【数据库知识扫描】 | SQL复习-中篇 第11课 使用子查询

本文详细介绍了SQL中的子查询概念,包括如何利用子查询进行过滤和作为计算字段使用。通过实例展示了在Orders和Customers表中如何通过子查询找到特定商品的购买者,以及计算每个顾客的订单总数。同时,文章提醒了子查询可能导致的性能问题,并强调在多表操作中使用完全限定列名避免歧义的重要性。
摘要由CSDN通过智能技术生成

意简言赅,这一课介绍什么是子查询,如何使用它们。

早学完,早睡觉。困极了。

目录

11.1 子查询

11.2 利用子查询进行过滤

11.3 作为计算字段使用子查询


11.1 子查询

查询(query)任何SQL语句都是查询。但此术语一般指SELECT语句。

目前学习的所有SELECT语句都是简单查询,即从单个数据库表中检索数据的单条语句。

子查询(subquery),即嵌套在其他查询中的查询。

讲到子查询,应该聊聊MySQL支持,对子查询的支持是从4.1版本引入的(面试可能考!注意)。MySQL的早期版本不支持子查询。

11.2 利用子查询进行过滤

主要研究的对象是关系表,订单存储在两个表中。每个订单包含订单编号、客户ID、订单日期,在Orders表中存储为一行。各订单的物品存储在相关的OrderItems表中。Orders表不存储顾客信息,只存储顾客ID。顾客的实际信息存储在Customers表中。

假使麻烦来了,需要列出订购物品RGAN01的所有顾客,怎么搞呢?

  1. 检索包含物品RGAN01的所有订单的编号。
  2. 检索具有前一步骤列出的订单编号的所有顾客的ID。
  3. 检索前一步骤返回的所有顾客ID的顾客信息。

起码要分这散步吧,拿到订单,拿到顾客,拿到顾客的信息才算结束。那么这三步检索,能不能把某条SELECT语句返回的结果用于另一条SELECT语句的WHERE子句呢?

来试试,先说好,分别练习的语句不放上来,只放截图,最后综合句一起放:

SELECT cust_id FROM Orders WHERE order_num IN (SELECT order_num FROM OrderItems WHERE prod_id = 'RGAN01');

在SELECT语句中,子查询总是从内向外处理。那么考虑内部查询,外部查询的话,可以看左图,上面的为右图的内部查询,下面的为外部查询。输出一样,返回值相同。

另补一句:格式化SQL。说拿颜色区别开来,将子查询分解成多行缩进,看的清晰明了。

现在得到了订购物品RGAN01的所有顾客的ID。下一步是检索这些顾客ID的顾客信息。也就是说,工作还没干完,但是是个好兆头,接着做剩下的部分:

拿前面的语法也能做,得到结果,over~停!我们这一课学的子查询,干啥不把三个一起呢???

接着来。

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'));

终于挖出最后的结果,并且和上面得到结果一致。

在WHERE子句中使用子查询能够编写出功能很强且很灵活的SQL语句。对于能嵌套的子查询的数目没有限制,不过在实际使用时由于性能的限制,不能嵌套太多的子查询。

子查询和性能这里给出的代码有效,并且获得了所需的结果。但是,使用子查询并不总是执行这类数据检索的最有效方法。往后看就知道了,下一课就不太行。

11.3 作为计算字段使用子查询

使用子查询的另一方法是创建计算字段。

比如说需要显示Customers表中每个顾客的订单总数。订单与相应的顾客ID存储在Orders表中。

那么为了拿到需要的结果,我们要:

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

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

统计数目好说,SELECT COUNT(*)对表中的行进行计数,还可以通过提供一条WHERE子句来过滤某个特定的顾客ID,仅对该顾客的订单进行计数。

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

这条SELECT语句对Customers表中每个顾客返回三列:cust_name、cust_state和orders。orders是一个计算字段,它是由圆括号中的子查询建立的。该子查询对检索出的每个顾客执行一次。在此例中,该子查询执行了5次,因为检索出了5个顾客。

(哈欠连天的我也忙不上给这段分析加注释了,直接copy上来了,主要是对于订单中顾客计数,然后再去检索出顾客信息)

用一个句点分隔表名和列名,在有可能混淆列名时必须使用这种语法。

子查询中的WHERE子句与前面使用的WHERE子句稍有不同,因为它使用了完全限定列名,而不只是列名(cust_id)。它指定表名和列名(Orders.cust_id和Customers.cust_id)。也就是在讲,上面不是Orders.cust_id吗?是避免跟Customers表中的搞混了。

然后书上为了验证这样干(没有前面表名起作用的完全限定名)是不好滴,得不到想要的结果,做了一个小测试:

看看,多么痛的领悟~拿到的数据完全不一样,简直崩溃!

虽然子查询在构造这种SELECT语句时有用,但必须注意限制有歧义的列。不要搞二义性这种东西。

如果在SELECT语句中操作多个表,就应使用完全限定列名(带个表名,做个人吧)来避免歧义。

不止一种解决方案,虽然为了熟悉语法,我们强行将很多样例代码都运行出来了,但是这不代表,这些就是解决数据检索的最优方法,后面学习,还会遇到更多问题更多组合解决方案,我们应当因地制宜,选择合适的解决方案。

这节课就在我的哈欠和不停得得得~中度过去了。因为笔记本电脑的鼠标“C”键一直自己按按按,家人又有需要,所以把笔记本和那个酷似网吧键盘的blingbling白键盘贡献出去了,配合上次入手的白鼠标,一套好看极了。

可没了键程舒适按压力道刚好的键盘的我,打字都不香了。这并不是我今天不学三课的原因。

明天见,刻意练习,每日精进。晚安。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值