首页 > 其他分享 >14. 使用子查询

14. 使用子查询

时间:2024-11-01 16:12:55浏览次数:1  
标签:14 orders 使用 查询 where id select cust

1. 子查询

SELECT语句是SQL的查询。迄今为止我们所看到的所有SELECT语句都是简单查询,即从单个数据库表中检索数据的单条语句。

补充:

  • 查询(query):

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

SQL还允许创建子查询(subquery),即嵌套在其他查询中的查询。

2. 利用子查询进行过滤

订单存储在两个表中。对于包含订单号、客户ID、订单日期的每个订单,orders表存储一行。各订单的物品存储在相关的orderitems表中。orders表不存储客户信息。它只存储客户的ID。实际的客户信息存储在customers表中。

现在,假如需要列出订购物品TNT2的所有客户,应该怎样检索?下面列出具体的步骤:

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

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

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

上述每个步骤都可以单独作为一个查询来执行。可以把一条SELECT语句返回的结果用于另一条SELECT语句的WHERE子句。

也可以使用子查询来把3个查询组合成一条语句。

  • 第一条SELECT语句的含义很明确,对于prod_id为TNT2的所有订单物
    品,它检索其order_num列。

    select order_num from orderitems
    where prod_id = 'TNT2';
    

    输出如下:

    img

    输出列出两个包含此物品的订单。

  • 下一步,查询具有订单20005和20007的客户ID。利用第7章介绍的IN
    子句,编写如下的SELECT语句:

    select cust_id from orders
    where order_num in (20005,20007)
    

    输出如下:

    img

  • 现在,把第一个查询(返回订单号的那一个)变为子查询组合两个
    查询。

    select cust_id from orders
    where order_num in (select order_num 
                        from orderitems
                        where prod_id = 'TNT2');
    

    输出如下:

    img

    在SELECT语句中,子查询总是从内向外处理。

    在处理上面的SELECT语句时,MySQL实际上执行了两个操作。

    首先,它执行下面的查询:

    select order_num from orderitems where prod_id = 'TNT2'
    

    此查询返回两个订单号:20005和20007。

    然后,这两个值以IN操作符要求的逗号分隔的格式传递给外部查询的WHERE子句。外部查询变成:

    select cust_id from orders where order_num in (20005,20007)
    

    可以看到,输出是正确的并且与前面硬编码WHERE子句所返回的值相同。

  • 现在得到了订购物品TNT2的所有客户的ID。下一步是检索这些客户ID的客户信息。

    select cust_name, cust_contact
    from customers
    where cust_id in (10001, 10004);
    

    可以把其中的WHERE子句转换为子查询而不是硬编码这些客户ID:

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

    输出如下:

    img

    为了执行上述SELECT语句,MySQL实际上必须执行3条SELECT语句。最里边的子查询返回订单号列表,此列表用于其外面的子查询的WHERE子句。外面的子查询返回客户ID列表,此客户ID列表用于最外层查询的WHERE子句。最外层查询确实返回所需的数据。

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

补充:

  • 列必须匹配:

    在WHERE子句中使用子查询(如这里所示),应该保证SELECT语句具有与WHERE子句中相同数目的列。(比如上面的where cust_id in (select cust_id where order_num in (select order_numcust_idcust_id对应,order_numorder_num对应)

    通常,子查询将返回单个列并且与单个列匹配,但如果需要也可以使用多个列。

  • 虽然子查询一般与IN操作符结合使用,但也可以用于测试等于(=)、不等于(<>)等。

  • 子查询和性能:

    这里给出的代码有效并获得所需的结果。但是,使用子查询并不总是执行这种类型的数据检索的最有效的方法。更多的论述,请参阅第15章,其中将再次给出这个例子。

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

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

假如需要显示customers表中每个客户的订单总数。订单与相应的客户ID存储在orders表中。

为了执行这个操作,遵循下面的步骤。

(1) 从customers表中检索客户列表。

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

正如前两章所述,可使用SELECT COUNT(*)对表中的行进行计数,并且通过提供一条WHERE子句来过滤某个特定的客户ID,可仅对该客户的订单进行计数。

  • 例如,下面的代码对客户10001的订单进行计数:

    select count(*) as orders
    from orders
    where cust_id = 10001;
    

    输出如下:

    img

  • 为了对每个客户执行COUNT(*)计算,应该将COUNT(*)作为一个子查询。

    select cust_name, 
            cust_state,
            (select count(*)
            from orders
            where orders.cust_id = customers.cust_id) as orders
    from customers
    order by cust_name;
    

    输出如下:

    img

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

    子查询中的WHERE子句与前面使用的WHERE子句稍有不同,因为它使用了完全限定列名(在第4章中首次提到)。下面的语句告诉SQL比较orders表中的cust_id与当前正从customers表中检索的cust_id:

    where orders.cust_id = customers.cust_id
    
  • 这种类型的子查询称为相关子查询(相关子查询: 涉及外部查询的子查询。)。任何时候只要列名可能有多义性,就必须使用这种语法(表名和列名由一个句点分隔)。

    为什么这样?我们来看看如果不使用完全限定的列名会发生什么情况:

    select cust_name, 
            cust_state,
            (select count(*)
            from orders
            where cust_id = cust_id) as orders
    from customers
    order by cust_name;
    

    输出如下:

    img

    显然,返回的结果不正确(请比较前面的结果),那么,为什么会这样呢?

    有两个cust_id列,一个在customers中,另一个在orders中,需要比较这两个列以正确地把订单与它们相应的顾客匹配。

    如果不完全限定列名,MySQL将假定你是对orders表中的cust_id进行自身比较。而SELECT COUNT(*) FROM orders WHERE cust_id = cust_id;总是返回orders表中的订单总数(因为MySQL查看每个订单的cust_id是否与本身匹配,当然,它们总是匹配的)。

虽然子查询在构造这种SELECT语句时极有用,但必须注意限制有歧义性的列名。

补充:

  • 相关子查询(correlated subquery):

    涉及外部查询的子查询。

  • 不止一种解决方案:

    正如本章前面所述,虽然这里给出的样例代码运行良好,但它并不是解决这种数据检索的最有效的方法。在后面的章节(第15章)中我们还要遇到这个例子。

  • 逐渐增加子查询来建立查询:

    用子查询测试和调试查询很有技巧性,特别是在这些语句的复杂性不断增加的情况下更是如此。

    用子查询建立(和测试)查询的最可靠的方法是逐渐进行,这与MySQL处理它们的方法非常相同

    首先,建立和测试最内层的查询。然后,用硬编码数据建立和测试外层查询,并且仅在确认它正常后才嵌入子查询。这时,再次测试它。对于要增加的每个查询,重复这些步骤。这样做仅给构造查询增加了一点点时间,但节省了以后(找出查询为什么不正常)的大量时间,并且极大地提高了查询一开始就正常工作的可能性。

    对上面这段话的理解:

    1. 建立和测试最内层的查询:

      从最基本的查询开始,通常是查询中最内部的部分(子查询)。先建立和测试这个查询,确保它能够返回正确的数据。

    2. 用硬编码数据建立和测试外层查询:

      一旦确认最内层的查询正常工作,就开始构建外层查询。此时,可以使用一些固定的(硬编码的)数据来测试外层查询的逻辑。

      例如,可以用具体的值代替从数据库中获取的值,确认外层查询能够正确处理这些数据。

    3. 仅在确认它正常后才嵌入子查询:

      当确认外层查询的逻辑没有问题后,才将之前测试过的最内层查询嵌入到外层查询中。这样可以确保外层查询的基础是稳固的。

      嵌入后再次运行整个查询,确保整合后依然能够得到预期的结果。

    4. 再次测试它:

      在完成所有的嵌套后,进行最后的测试,确保整个查询的逻辑和数据返回都符合期望。

标签:14,orders,使用,查询,where,id,select,cust
From: https://www.cnblogs.com/hisun9/p/18520463

相关文章

  • GA/T1400视图库平台EasyCVR视频分析设备平台微信H5小程序:智能视频监控的新篇章
    GA/T1400视图库平台EasyCVR是一款综合性的视频管理工具,它兼容Windows、Linux(包括CentOS和Ubuntu)以及国产操作系统。这个平台不仅能够接入多种协议,还能将不同格式的视频数据统一转换为标准化的视频流,通过无需插件的H5直播技术,在网页端实现多格式视频的流畅播放。这种特性极大地增强......
  • 【Mysql自学笔记(黑马程序员)】基础篇(三)SQL常用语法分类——DQL(数据查询语言)(篇一)基本查
    SQL常用语法分类——DQL(数据查询语言)(篇一)——基本查询、条件查询、聚合函数一、概述1、什么是DQL?2、本文内容二、DQL语句介绍0、前言1、基本查询2、条件查询3、聚合函数本专栏将会持续更新,旨在为大家源源不断地呈现更多有帮助的Mysql学习内容。以下是之前更新的两......
  • 安卓APP开发中,如何使用加密芯片?
    加密芯片是一种专门设计用于保护信息安全的硬件设备,它通过内置的加密算法对数据进行加密和解密,以防止敏感数据被窃取或篡改。如下图HD-RK3568-IOT工控板,搭载ATSHA204A加密芯片,常用于有安全防护要求的工商业场景,下文将为大家介绍安卓APP开发中,如何使用此类加密芯片。1. Android......
  • 使用python爬虫爬取热门文章分析最新技术趋势
    本文借助爬虫来分析哪些技术正在快速发展,哪些问题在开发者中引起广泛讨论,从而为学习和研究提供重要参考。使用python爬虫分析最新技术趋势一、爬取目标二、代码环境2.1编程语言2.2三方库2.3环境配置三、代码实战3.1接口分析3.2接口参数分析接口地址请求方法描述......
  • 如何使用WebSockets在网页应用中实现实时通信
    摘要:实现网页应用中的实时通信,1、选择合适的WebSockets库以简化实施过程;2、在服务器端与客户端建立WebSocket连接;3、设计有效的消息协议;4、确保通信安全性;5、处理网络问题和重连机制。其中选择合适的WebSockets库是基础。它能够帮助开发者快速构建实时通信功能,如Socket.IO、Web......
  • 【Linux内核】Cgroup原理和使用
    1.Cgroup简介cgroups(ControlGroups)是Linux内核的一个特性,用于对进程组的物理资源(如CPU、内存、磁盘I/O等)进行细粒度的控制和监控。cgroups可以帮助你限制、记录和隔离资源使用,但它本身并不直接用来“拉高CPU负载”。相反,cgroups通常用于限制进程可以使用的资源量,以防止它们消耗......
  • Qt5.9使用QWebEngineView加载网页速度慢 ,卡顿,原因是默认开启了代理
     Qt5.9使用QWebEngineView加载网页速度慢,卡顿,原因是默认开启了代理https://blog.csdn.net/zhanglixin999/article/details/131161944 BUG单下的留言讲明了问题发生的原因,那就是系统默认设置为自动寻找代理,而使用代理后延迟会变得非常大。(1)关闭自动代理接的pro文件内添......
  • 【Kettle的安装与使用】使用Kettle实现mysql和hive的数据传输(使用Kettle将mysql数据导
    文章目录一、安装1、解压2、修改字符集3、启动二、实战1、将hive数据导入mysql2、将mysql数据导入到hive一、安装Kettle的安装包在文章结尾1、解压在windows中解压到一个非中文路径下2、修改字符集修改spoon.bat文件"-Dfile.encoding=UTF-8"3、启动以......
  • Asp.net 使用FluentScheduler
     1.安装包:Install-PackageFluentScheduler2.  Global.asax添加JobManager.Initialize(newMyRegister());3.添加类 publicclassMyRegister:Registry{publicMyRegister(){//ScheduleanIJobtorunataninte......
  • 使用PHP构建命令行应用的技巧
    ###使用PHP构建命令行应用的技巧在开头,我们直接回答使用PHP构建命令行应用的技巧:选择合适的库、理解命令行界面(CLI)的基本原理、熟悉PHPCLI的内置功能、编写可维护的代码、进行彻底的测试。其中,选择合适的库是基础且关键的一步。使用如SymfonyConsole或LaravelZero等库可以大......