SQL 关联子查询[通俗易懂]

SQL 关联子查询[通俗易懂]学习重点 关联子查询会在细分的组内进行比较时使用。 关联子查询和 GROUP BY 子句一样,也可以对表中的数据进行切分。 关联子查询的结合条件如果未出现在子查询之中就会发生错误。 一、普通的子查询和

SQL 关联子查询

目录
  • 一、普通的子查询和关联子查询的区别
  • 二、关联子查询也是用来对集合进行切分的
  • 三、结合条件一定要写在子查询中
  • 请参阅

学习重点

  • 关联子查询会在细分的组内进行比较时使用。

  • 关联子查询和 GROUP BY 子句一样,也可以对表中的数据进行切分。

  • 关联子查询的结合条件如果未出现在子查询之中就会发生错误。

一、普通的子查询和关联子查询的区别

按此前所学,使用子查询就能选取出销售单价(sale_price)高于全部商品平均销售单价的商品。这次我们稍稍改变一下条件,选取出各商品种类中高于该商品种类的平均销售单价的商品。

  • 按照商品种类与平均销售单价进行比较

    只通过语言描述可能难以理解,还是让我们来看看具体示例吧。我们以厨房用具中的商品为例,该分组中包含了表 1 所示的 4 种商品。

    表 1 厨房用具中的商品

    商品名称 销售单价
    菜刀 3000
    高压锅 6800
    叉子 500
    擦菜板 880

    因此,计算上述 4 种商品的平均价格的算术式如下所示。

    (3000 + 6800 + 500 + 880) / 4 = 2795 (日元)

    这样我们就能得知该分组内高于平均价格的商品是菜刀和高压锅了,这两种商品就是我们要选取的对象。

    我们可以对余下的分组继续使用同样的方法。衣服分组的平均销售单价是:

    (1000 + 4000) / 2 = 2500 (日元)

    因此运动T恤就是要选取的对象。办公用品分组的平均销售单价是:

    (500 + 100) / 2 = 300 (日元)

    因此打孔器就是我们要选取的对象。

    这样大家就能明白该进行什么样的操作了吧。我们并不是要以全部商品为基础,而是要以细分的组为基础,对组内商品的平均价格和各商品的销售单价进行比较。

    按照商品种类计算平均价格并不是什么难事,我们已经学习过了,只需按照代码清单 15 那样,使用 GROUP BY 子句就可以了。

    代码清单 15 按照商品种类计算平均价格

    SELECT AVG(sale_price)
    FROM Product
    GROUP BY product_type;
    

    但是,如果我们使用前一节(标量子查询)的方法,直接把上述 SELECT 语句使用到 WHERE 子句当中的话,就会发生错误。

    -- 发生错误的子查询
    SELECT product_id, product_name, sale_price
    FROM Product
    WHERE sale_price > (SELECT AVG(sale_price)
                            FROM Product
                            GROUP BY product_type);
    

    出错原因前一节已经讲过了,该子查询会返回 3 行结果(2795、2500、300),并不是标量子查询。在 WHERE 子句中使用子查询时,该子查询的结果必须是单一的。

    但是,如果以商品种类分组为单位,对销售单价和平均单价进行比较,除此之外似乎也没有其他什么办法了。到底应该怎么办才好呢?

  • 使用关联子查询的解决方案

    这时就轮到我们的好帮手——关联子查询登场了。

    KEYWORD

    • 关联子查询

    只需要在刚才的 SELECT 语句中追加一行,就能得到我们想要的结果了 [1]。事实胜于雄辩,还是让我们先来看看修改之后的 SELECT 语句吧(代码清单 16)。

    代码清单 16 通过关联子查询按照商品种类对平均销售单价进行比较

    通过关联子查询按照商品种类对平均销售单价进行比较

    特定的 SQL

    Oracle 中不能使用 AS(会发生错误)。因此,在 Oracle 中执行代码清单 16 时,请大家把 ① 中的 FROM Product AS P1 变为 FROM Product P1,把 ② 中的 FROM Product AS P2 变为 FROM Product P2

    执行结果

    product_type  | product_name  | sale_price
    ---------------+---------------+------------
    办公用品      | 打孔器         |        500
    衣服          | 运动T恤        |       4000
    厨房用具      | 菜刀           |       3000
    厨房用具      | 高压锅         |       6800
    

    这样我们就能选取出办公用品、衣服和厨房用具三类商品中高于该类商品的平均销售单价的商品了。

    这里起到关键作用的就是在子查询中添加的 WHERE 子句的条件。该条件的意思就是,在同一商品种类中对各商品的销售单价和平均单价进行比较。

    这次由于作为比较对象的都是同一张 Product 表,因此为了进行区别,分别使用了 P1P2 两个别名。在使用关联子查询时,需要在表所对应的列名之前加上表的别名,以“<表名>.<列名>”的形式记述。

    在对表中某一部分记录的集合进行比较时,就可以使用关联子查询。因此,使用关联子查询时,通常会使用“限定(绑定)”或者“限制”这样的语言,例如本次示例就是限定“商品种类”对平均单价进行比较。

    法则 8

    在细分的组内进行比较时,需要使用关联子查询。

二、关联子查询也是用来对集合进行切分的

换个角度来看,其实关联子查询也和 GROUP BY 子句一样,可以对集合进行切分。

大家还记得我们用来说明 GROUP BY 子句的图(图 6)吗?

根据商品种类对表进行切分的图示

图 6 根据商品种类对表进行切分的图示

上图显示了作为记录集合的表是如何按照商品种类被切分的。使用关联子查询进行切分的图示也基本相同(图 7)。

根据关联子查询进行切分的图示

图 7 根据关联子查询进行切分的图示

我们首先需要计算各个商品种类中商品的平均销售单价,由于该单价会用来和商品表中的各条记录进行比较,因此关联子查询实际只能返回 1 行结果。这也是关联子查询不出错的关键。关联子查询执行时,DBMS 内部的执行情况如图 8 所示。

关联子查询执行时 DBMS 内部的执行情况

图 8 关联子查询执行时 DBMS 内部的执行情况

如果商品种类发生了变化,那么用来进行比较的平均单价也会发生变化,这样就可以将各种商品的销售单价和平均单价进行比较了。关联子查询的内部执行结果对于初学者来说是比较难以理解的,但是像上图这样将其内部执行情况可视化之后,理解起来就变得非常容易了吧。

三、结合条件一定要写在子查询中

下面给大家介绍一下 SQL 初学者在使用关联子查询时经常犯的一个错误,那就是将关联条件写在子查询之外的外层查询之中。请大家看一下下面这条 SELECT 语句。

错误的关联子查询书写方法

上述 SELECT 语句只是将子查询中的关联条件移到了外层查询之中,其他并没有任何更改。但是,该 SELECT 语句会发生错误,不能正确执行。允许存在这样的书写方法可能并不奇怪,但是 SQL 的规则禁止这样的书写方法。

该书写方法究竟违反了什么规则呢?那就是关联名称作用域。虽然这一术语看起来有些晦涩难懂,但是一解释大家就明白了。关联名称就是像 P1P2 这样作为表别名的名称,作用域(scope)就是生存范围(有效范围)。也就是说,关联名称存在一个有效范围的限制。

KEYWORD

  • 关联名称

  • 作用域

具体来讲,子查询内部设定的关联名称,只能在该子查询内部使用(图 9)。换句话说,就是“内部可以看到外部,而外部看不到内部”。

请大家一定不要忘记关联名称具有一定的有效范围。如前所述,SQL 是按照先内层子查询后外层查询的顺序来执行的。这样,子查询执行结束时只会留下执行结果,作为抽出源的 P2 表其实已经不存在了 [2]。因此,在执行外层查询时,由于 P2 表已经不存在了,因此就会返回“不存在使用该名称的表”这样的错误。

子查询内的关联名称的有效范围

图 9 子查询内的关联名称的有效范围

请参阅

  • 视图
  • 子查询
  • 关联子查询

(完)


  1. 事实上,对于代码清单 16 中的 SELECT 语句,即使在子查询中不使用 GROUP BY 子句,也能得到正确的结果。这是因为在 WHERE 子句中追加了“P1.product_type=P2.product_type”这个条件,使得 AVG 函数按照商品种类进行了平均值计算。但是为了跟前面出错的查询进行对比,这里还是加上了 GROUP BY 子句。 ↩︎

  2. 当然,消失的其实只是 P2 这个名称而已,Product 表以及其中的数据还是存在的。 ↩︎

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/5683.html

(0)
上一篇 2023-04-29
下一篇 2023-04-29

相关推荐

  • Python使用log10()函数对数值100进行对数变换

    Python使用log10()函数对数值100进行对数变换log10()函数是Python内置的数学函数之一,用于返回数字的以10为底的对数,即log10(x)返回的是log(x)以10为底的对数。在Python中,该函数的使用方法为:import math后直接调用math.log10(x)即可,其中x代表需要进行对数变换的数值。需要注意的是,在使用log10()函数时,x的取值不能为0或负数,否则会报错。

    2024-01-07
    107
  • 面试官:说出八种消息队列的应用场景。啊?八种?

    面试官:说出八种消息队列的应用场景。啊?八种?本文来源于公众号:胖滚猪学编程。转载请注明出处! 一个风度翩翩,穿着格子衬衣的中年男子,拿着一个满是划痕的mac向她走来,看着铮亮的头,胖滚猪心想,这肯定是尼玛顶级架构师吧!完了要挂了。 结果面试官第

    2023-03-04
    159
  • 事务隔离性和隔离级别

    事务隔离性和隔离级别隔离性是当多个用户并发访问数据库时,比如同时操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离 事务的隔离级别有哪些? 一、概念 Read uncom

    2023-04-20
    152
  • GROUP BY中的WITH CUBE、WITH ROLLUP原理测试及GROUPING应用[通俗易懂]

    GROUP BY中的WITH CUBE、WITH ROLLUP原理测试及GROUPING应用[通俗易懂]前几天,看到一个群友用WITH ROLLUP运算符。由于自个儿没用过,看到概念及结果都云里雾里的,所以突然来了兴趣对生成结果测了一番。 一、概念: WITH CUBE:生成的结果集显示了所选列中值的所

    2022-12-16
    138
  • 9个GaussDB常用的对象语句[亲测有效]

    9个GaussDB常用的对象语句[亲测有效]摘要:本文介绍了9个GaussDB常用的对象语句,希望对大家有帮助。 本文分享自华为云社区《GaussDB对象相关语句》,作者:酷哥。 1. 常用函数 pg_database_size() 数据

    2023-06-14
    144
  • hpux 下 crontab无权创建的的问题解决

    hpux 下 crontab无权创建的的问题解决1、Oracle用户没有权限执行crontab 引用 $ crontab -e crontab: you are not authorized to use cron. Sorry. $ exit …

    2022-12-21
    141
  • 创建漂亮的用户界面 – 了解Python的Tkinter GUI框架

    创建漂亮的用户界面 – 了解Python的Tkinter GUI框架Tkinter是Python标准库中的一个GUI(图形用户界面)工具包。它为Python程序提供了一个本地的、跨平台的GUI环境。Tkinter简单易用,是学习Python GUI编程的一个不错的入门框架。在这篇文章中,我们将深入探讨Tkinter库,并提供一些例子和技巧,以帮助您更好地理解GUI编程的概念和工作原理。

    2024-01-04
    108
  • HBase/TiDB都在用的数据结构:LSM Tree,不得了解一下?[通俗易懂]

    HBase/TiDB都在用的数据结构:LSM Tree,不得了解一下?[通俗易懂]LSMTree(Log-structuredmerge-tree)广泛应用在HBase,TiDB等诸多数据库和存储引擎上,我们先来看一下它的一些应用:这么牛X的名单,你不想了解下LSMTree吗?装…

    2023-04-04
    143

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注