欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-14 11:07:15
...

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

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

目录

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子句呢?

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

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

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

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

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

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

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

拿前面的语法也能做,得到结果,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'));

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

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

在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;

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

这条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表中的搞混了。

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

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

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

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

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

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

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

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

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