本笔记为阿里云天池龙珠计划SQL训练营的学习内容,链接为:https://tianchi.aliyun.com/specials/promotion/aicampsql

目录

  • 一、表的加减法
    • 1.1 什么是集合运算
    • 1.2 表的加法–UNION
      • 1.2.1 UNION
      • 1.2.2UNION 与 OR 谓词
      • 1.2.3 包含重复行的集合运算 UNION ALL
      • 1.2.4[扩展阅读]bag 模型与 set 模型
      • 1.2.5隐式类型转换
    • 1.3 MySQL 8.0 不支持交运算INTERSECT
      • 1.3.1[扩展阅读]bag 的交运算
    • 1.4 差集,补集与表的减法
      • 1.4.1 MySQL 8.0 还不支持 EXCEPT 运算
      • 1.4.2 EXCEPT 与 NOT 谓词
      • 1.4.3EXCEPT ALL 与bag 的差
      • 1.4.4 INTERSECT 与 AND 谓词
    • 1.5对称差
      • 1.5.1借助并集和差集迂回实现交集运算 INTERSECT
  • 二、连结(JOIN)
    • 2.1 内连结(INNER JOIN)
      • 2.1.1 使用内连结从两个表获取信息
      • 2.1.2 结合 WHERE 子句使用内连结
      • 2.1.3结合 GROUP BY 子句使用内连结
      • 2.1.4自连结(SELF JOIN)
      • 2.1.5内连结与关联子查询
      • 2.1.6自然连结(NATURAL JOIN)
      • 2.1.7使用连结求交集
    • 2.2 外连结(OUTER JOIN)
      • 2.2.1 左连结与右连接
      • 2.2.2 使用左连结从两个表获取信息
      • 2.2.3结合 WHERE 子句使用左连结
      • 2.2.4在 MySQL 中实现全外连结
    • 2.3多表连结
      • 2.3.1 多表进行内连结
      • 2.3.2多表进行外连结
    • 2.4 ON 子句进阶–非等值连结
      • 2.4.1非等值自左连结(SELF JOIN)
    • 2.5 交叉连结—— CROSS JOIN(笛卡尔积)
      • 2.5.1[扩展阅读]连结与笛卡儿积的关系
    • 2.6 连结的特定语法和过时语法
  • 三、练习题
    • 3.1 练习题1
    • 3.2 练习题2
    • 3.3 练习题3
    • 3.4 练习题4
    • 3.5 练习题5
  • 四、小结

一、表的加减法

1.1 什么是集合运算

集合在数学领域表示“各种各样的事物的总和”, 在数据库领域表示记录的集合. 具体来说,表、视图和查询的执行结果都是记录的集合, 其中的元素为表或者查询结果中的每一行。

在标准 SQL 中, 分别对检索结果使用 UNION, INTERSECT, EXCEPT 来将检索结果进行并,交和差运算, 像UNION,INTERSECT, EXCEPT这种用来进行集合运算的运算符称为集合运算符。

以下的文氏图展示了几种集合的基本运算.
在这里插入图片描述
在这里插入图片描述
[图片来源于网络]

在数据库中, 所有的表–以及查询结果–都可以视为集合, 因此也可以把表视为集合进行上述集合运算, 在很多时候, 这种抽象非常有助于对复杂查询问题给出一个可行的思路.

1.2 表的加法–UNION

1.2.1 UNION

建表代码及数据导入请使用第一章提供的代码.
由于前面没有导入product2这个表,教程疏忽了,这里补充一下:

CREATE TABLE `product2` (`product_id` char(4) NOT NULL,`product_name` varchar(100) NOT NULL,`product_type` varchar(32) NOT NULL,`sale_price` int DEFAULT NULL,`purchase_price` int DEFAULT NULL,`regist_date` date DEFAULT NULL,PRIMARY KEY (`product_id`)
) ;
INSERT INTO `product2`(`product_id`, `product_name`, `product_type`, `sale_price`, `purchase_price`, `regist_date`) VALUES ('0001', 'T恤衫', '衣服', 1000, 500, '2009-09-20');
INSERT INTO `product2`(`product_id`, `product_name`, `product_type`, `sale_price`, `purchase_price`, `regist_date`) VALUES ('0002', '打孔器', '办公用品', 500, 320, '2009-09-11');
INSERT INTO `product2`(`product_id`, `product_name`, `product_type`, `sale_price`, `purchase_price`, `regist_date`) VALUES ('0003', '运动T恤', '衣服', 4000, 2800, NULL);
INSERT INTO `product2`(`product_id`, `product_name`, `product_type`, `sale_price`, `purchase_price`, `regist_date`) VALUES ('0009', '手套', '衣服', 800, 500, NULL);
INSERT INTO `product2`(`product_id`, `product_name`, `product_type`, `sale_price`, `purchase_price`, `regist_date`) VALUES ('0010', '水壶', '厨房用具', 2000, 1700, '2009-09-20');

接下来我们演示UNION的具体用法及查询结果:

SELECT product_id, product_nameFROM productUNION
SELECT product_id, product_nameFROM product2;

在这里插入图片描述

上述结果包含了两张表中的全部商品. 你会发现,这就是我们在学校学过的集合中的并集运算,通过文氏图会看得更清晰(图 7-1):
在这里插入图片描述
通过观察可以发现,商品编号为“ 0001 ”~“ 0003 ”的 3 条记录在两个表中都存在,因此大家可能会认为结果中会出现重复的记录,但是 UNION 等集合运算符通常都会除去重复的记录.

上述查询是对不同的两张表进行求并集运算. 对于同一张表, 实际上也是可以进行求并集的.

**练习题:**假设连锁店想要增加毛利率超过 50%或者售价低于 800 的货物的存货量, 请使用 UNION 对分别满足上述两个条件的商品的查询结果求并集.

结果应该类似于:
在这里插入图片描述

SELECT  product_id,product_name,product_type,sale_price,purchase_priceFROM product WHERE sale_price<800UNIONSELECT  product_id,product_name,product_type,sale_price,purchase_priceFROM product WHERE sale_price>1.5*purchase_price;

在这里插入图片描述
思考: 如果不使用 UNION 该怎么写查询语句?

SELECT  product_id,product_name,product_type,sale_price,purchase_priceFROM product WHERE sale_price<800 or sale_price>1.5*purchase_price;

在这里插入图片描述

1.2.2UNION 与 OR 谓词

对于上边的练习题, 如果你已经正确地写出来查询, 你会发现, 使用 UNION 对两个查询结果取并集, 和在一个查询中使用 WHERE 子句, 然后使用 OR 谓词连接两个查询条件, 能够得到相同的结果.

那么是不是就没必要引入 UNION 了呢? 当然不是这样的. 确实, 对于同一个表的两个不同的筛选结果集, 使用 UNION 对两个结果集取并集, 和把两个子查询的筛选条件用 OR 谓词连接, 会得到相同的结果, 但倘若要将两个不同的表中的结果合并在一起, 就不得不使用 UNION 了.

而且, 即便是对于同一张表, 有时也会出于查询效率方面的因素来使用 UNION.

练习题 :

分别使用 UNION 或者 OR 谓词,找出毛利率不足 30%或毛利率未知的商品.

OR 谓词

SELECT  product_id,product_name,product_type,sale_price,purchase_priceFROM product WHERE sale_price < purchase_price * 1.3 or purchase_price IS NULL;

UNION 谓词

SELECT * FROM product WHERE sale_price < purchase_price * 1.3UNION
SELECT * FROM product WHERE purchase_price IS NULL;

1.2.3 包含重复行的集合运算 UNION ALL

在1.1.1 中我们发现, SQL 语句的 UNION 会对两个查询的结果集进行合并和去重, 这种去重不仅会去掉两个结果集相互重复的, 还会去掉一个结果集中的重复行. 但在实践中有时候需要需要不去重的并集, 在 UNION 的结果中保留重复行的语法其实非常简单,只需要在 UNION 后面添加 ALL 关键字就可以了.

例如, 想要知道 product 和 product2 中所包含的商品种类及每种商品的数量, 第一步,就需要将两个表的商品种类字段选出来, 然后使用 UNION ALL 进行不去重地合并. 接下来再对两个表的结果按 product_type 字段分组计数.

-- 保留重复行
SELECT product_id, product_nameFROM productUNION ALL
SELECT product_id, product_nameFROM product2;

查询结果如下:
在这里插入图片描述
练习题:

商店决定对product表中利润低于50%和售价低于1000的商品提价, 请使用UNION ALL 语句将分别满足上述两个条件的结果取并集. 查询结果类似下表:
在这里插入图片描述

SELECT *FROM productWHERE sale_price / purchase_price > 1.5UNION ALL
SELECT *FROM productWHERE sale_price < 1000;

在这里插入图片描述

1.2.4[扩展阅读]bag 模型与 set 模型

在高中数学课上我们就学过, 集合的一个显著的特征就是集合中的元素都是互异的. 当我们把数据库中的表看作是集合的时候, 实际上存在一些问题的: 不论是有意的设计或无意的过失, 很多数据库中的表包含了重复的行.

Bag 是和 set 类似的一种数学结构, 不一样的地方在于: bag 里面允许存在重复元素, 如果同一个元素被加入多次, 则袋子里就有多个该元素.

通过上述 bag 与 set 定义之间的差别我们就发现, 使用 bag 模型来描述数据库中的表在很多时候更加合适.

是否允许元素重复导致了 set 和 bag 的并交差等运算都存在一些区别. 以 bag 的交为例, 由于 bag 允许元素重复出现, 对于两个 bag, 他们的并运算会按照: 1. 该元素是否至少在一个 bag 里出现过
2. 该元素在两个 bag 中的最大出现次数 这两个方面来进行计算.
因此对于 A = {1,1,1,2,3,5,7}, B = {1,1,2,2,4,6,8} 两个 bag, 它们的并就等于 {1,1,1,2,2,3,4,5,6,7,8}.

1.2.5隐式类型转换

通常来说, 我们会把类型完全一致, 并且代表相同属性的列使用 UNION 合并到一起显示, 但有时候, 即使数据类型不完全相同, 也会通过隐式类型转换来将两个类型不同的列放在一列里显示, 例如字符串和数值类型:

SELECT product_id, product_name, '1'FROM productUNION
SELECT product_id, product_name,sale_priceFROM product2;

上述查询能够正确执行,得到如下结果:
在这里插入图片描述
练习题:

使用 SYSDATE()函数可以返回当前日期时间, 是一个日期时间类型的数据, 试测试该数据类型和数值,字符串等类型的兼容性.
例如, 以下代码可以正确执行, 说明时间日期类型和字符串,数值以及缺失值均能兼容.

SELECT SYSDATE(), SYSDATE(), SYSDATE()UNIONSELECT 'chars', 123,  null

上述代码的查询结果:

在这里插入图片描述

1.3 MySQL 8.0 不支持交运算INTERSECT

集合的交, 就是两个集合的公共部分, 由于集合元素的互异性, 集合的交只需通过文氏图就可以很直观地看到它的意义.

虽然集合的交运算在SQL标准中已经出现多年了, 然而很遗憾的是, 截止到 MySQL 8.0 版本, MySQL 仍然不支持 INTERSECT 操作.

SELECT product_id, product_nameFROM productINTERSECT
SELECT product_id, product_nameFROM product2

错误:

1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘SELECT product_id,product_name
FROM product2’ at line 6

1.3.1[扩展阅读]bag 的交运算

对于两个 bag, 他们的交运算会按照:

  1. 该元素是否同时属于两个 bag
  2. 该元素在两个 bag 中的最小出现次数这两个方面来进行计算.

因此对于 A = {1,1,1,2,3,5,7}, B = {1,1,2,2,4,6,8} 两个 bag, 它们的交运算结果就等于 {1,1,2}.

1.4 差集,补集与表的减法

求集合差集的减法运算和实数的减法运算有些不同, 当使用一个集合A减去另一个集合B的时候,对于只存在于集合B而不存在于集合A的元素, 采取直接忽略的策略,因此集合A和B做减法只是将集合A中也同时属于集合B的元素减掉。
在这里插入图片描述

1.4.1 MySQL 8.0 还不支持 EXCEPT 运算

MySQL 8.0 还不支持 表的减法运算符 EXCEPT. 不过, 借助第六章学过的NOT IN 谓词, 我们同样可以实现表的减法.
练习题:
找出只存在于product表但不存在于product2表的商品.

SELECT *FROM productWHERE product_id NOT IN (SELECT product_id FROM product2)

在这里插入图片描述

1.4.2 EXCEPT 与 NOT 谓词

通过上述练习题的MySQL解法, 我们发现, 使用 NOT IN 谓词, 基本上可以实现和SQL标准语法中的EXCEPT运算相同的效果.
练习题:

使用NOT谓词进行集合的减法运算, 求出product表中, 售价高于2000,但利润低于30%的商品, 结果应该如下表所示.
在这里插入图片描述

SELECT *FROM productWHERE sale_price >2000 and product_id NOT in (SELECT product_idFROM productWHERE sale_price / purchase_price < 1.3)

在这里插入图片描述

1.4.3EXCEPT ALL 与bag 的差

类似于UNION ALL, EXCEPT ALL 也是按出现次数进行减法, 也是使用bag模型进行运算.

对于两个 bag, 他们的差运算会按照:

  1. 该元素是否属于作为被减数的 bag,
  2. 该元素在两个 bag 中的出现次数

这两个方面来进行计算. 只有属于被减数的bag的元素才参与EXCEP ALL运算, 并且差bag中的次数,等于该元素在两个bag的出现次数之差(差为零或负数则不出现). 因此对于 A = {1,1,1,2,3,5,7}, B = {1,1,2,2,4,6,8} 两个 bag, 它们的差就等于 {1,3,5,7}.

1.4.4 INTERSECT 与 AND 谓词

对于同一个表的两个查询结果而言, 他们的交INTERSECT实际上可以等价地将两个查询的检索条件用AND谓词连接来实现.

练习题:

使用AND谓词查找product表中利润率高于50%,并且售价低于1500的商品,查询结果如下所示.
在这里插入图片描述

SELECT *FROM productWHERE sale_price / purchase_price > 1.5 and sale_price < 1500

在这里插入图片描述

1.5对称差

两个集合A,B的对称差是指那些仅属于A或仅属于B的元素构成的集合. 对称差也是个非常基础的运算, 例如, 两个集合的交就可以看作是两个集合的并去掉两个集合的对称差.上述方法在其他数据库里也可以用来简单地实现表或查询结果的对称差运算: 首先使用UNION求两个表的并集, 然后使用INTERSECT求两个表的交集, 然后用并集减去交集, 就得到了对称差.

但由于在MySQL 8.0 里, 由于两个表或查询结果的并不能直接求出来, 因此并不适合使用上述思路来求对称差. 好在还有差集运算可以使用. 从直观上就能看出来, 两个集合的对称差等于 A-B并上B-A, 因此实践中可以用这个思路来求对称差
练习题:

使用product表和product2表的对称差来查询哪些商品只在其中一张表, 结果类似于:
在这里插入图片描述
提示: 使用 NOT IN 实现两个表的差集.

SELECT *FROM productWHERE product_id NOT IN (SELECT product_id FROM product2)UNIONSELECT *FROM product2WHERE product_id NOT IN (SELECT product_id FROM product)

在这里插入图片描述

1.5.1借助并集和差集迂回实现交集运算 INTERSECT

通过观察集合运算的文氏图, 我们发现, 两个集合的交可以看作是两个集合的并去掉两个集合的对称差。

二、连结(JOIN)

前一节我们学习了 UNION和INTERSECT 等集合运算, 这些集合运算的特征就是以行方向为单位进行操作. 通俗地说, 就是进行这些集合运算时, 会导致记录行数的增减. 使用 UNION 会增加记录行数,而使用 INTERSECT 或者 EXCEPT 会减少记录行数.

但这些运算不能改变列的变化, 虽然使用函数或者 CASE表达式等列运算, 可以增加列的数量, 但仍然只能从一张表中提供的基础信息列中获得一些"引申列", 本质上并不能提供更多的信息. 如果想要从多个表获取信息, 例如, 如果我们想要找出某个商店里的衣服类商品的名称,数量及价格等信息, 则必须分别从shopproduct 表和product 表获取信息.
在这里插入图片描述

注: 截至目前,本书中出现的示例(除了关联子查询)基本上都是从一张表中选取数据,但实际上,期望得到的数据往往会分散在不同的表之中,
这时候就需要使用连结了. 之前在学习关联子查询时我们发现, 使用关联子查询也可以从其他表获取信息, 但连结更适合从多张表获取信息.

连结(JOIN)就是使用某种关联条件(一般是使用相等判断谓词"="), 将其他表中的列添加过来, 进行“添加列”的集合运算. 可以说,连结是 SQL 查询的核心操作, 掌握了连结, 能够从两张甚至多张表中获取列, 能够将过去使用关联子查询等过于复杂的查询简化为更加易读的形式, 以及进行一些更加复杂的查询.

SQL 中的连结有多种分类方法, 我们这里使用最基础的内连结和外连结的分类方法来分别进行讲解.

2.1 内连结(INNER JOIN)

内连结的语法格式是:

-- 内连结
FROM <tb_1> INNER JOIN <tb_2> ON <condition(s)>

其中 INNER 关键词表示使用了内连结, 至于内连结的涵义, 目前暂时可以不必细究.
例如, 还是刚才那个问题:

找出某个商店里的衣服类商品的名称,数量及价格等信息.

我们进一步把这个问题明确化:

找出东京商店里的衣服类商品的商品名称,商品价格,商品种类,商品数量信息.

2.1.1 使用内连结从两个表获取信息

我们先来分别观察所涉及的表,product 表保存了商品编号,商品名称,商品种类等信息,这个表可以提供关于衣服种类的衣服的详细信息, 但是不能提供商店信息.
在这里插入图片描述
我们接下来观察shopproduct 表, 这个表里有商店编号名称,商店的商品编号及数量. 但要想获取商品的种类及名称售价等信息,则必须借助于product 表.
在这里插入图片描述
所以问题的关键是, 找出一个类似于"轴"或者"桥梁"的公共列, 将两张表用这个列连结起来. 这就是连结运算所要作的事情.

我们来对比一下上述两张表, 可以发现, 商品编号列是一个公共列, 因此很自然的事情就是用这个商品编号列来作为连接的“桥梁”,将product和shopproduct这两张表连接起来。
在这里插入图片描述

注:
如果你使用过 excel 的 vlookup 函数, 你会发现这个函数正好也能够实现这个功能. 实际上, 在思路上, 关联子查询更像是
vlookup 函数: 以表 A 为主表, 然后根据表 A 的关联列的每一行的取值,逐个到表 B 中的关联列中去查找取值相等的行.
当数据量较少时, 这种方式并不会有什么性能问题, 但数据量较大时, 这种方式将会导致较大的计算开销: 对于外部查询返回的每一行数据,
都会向内部的子查询传递一个关联列的值, 然后内部子查询根据传入的值执行一次查询然后返回它的查询结果. 这就使得,
例如外部主查询的返回结果有一万行, 那么子查询就会执行一万次, 这将会带来非常恐怖的时间消耗.

我们把上述问题进行分解:
首先, 找出每个商店的商店编号, 商店名称, 商品编号, 商品名称, 商品类别, 商品售价,商品数量信息.

按照内连结的语法, 在 FROM 子句中使用 INNER JOIN 将两张表连接起来, 并为 ON 子句指定连结条件为 shopproduct.product_id=product.product_id, 就得到了如下的查询语句:

SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.product_type,P.sale_price,SP.quantityFROM shopproduct AS SPINNER JOIN product AS PON SP.product_id = P.product_id;

在上述查询中, 我们分别为两张表指定了简单的别名, 这种操作在使用连结时是非常常见的, 通过别名会让我们在编写查询时少打很多字, 并且更重要的是, 会让查询语句看起来更加简洁.
上述查询将会得到如下的结果:
在这里插入图片描述
观察查询结果, 我们看到,这个结果里的列已经包含了所有我们需要的信息.

关于内连结,需要注意以下三点:

要点一: 进行连结时需要在 FROM 子句中使用多张表.

之前的 FROM 子句中只有一张表, 而这次我们同时使用了shopproduct 和product 两张表,使用关键字 INNER JOIN 就可以将两张表连结在一起了:

FROM shopproduct AS SP INNER JOIN product AS P

要点二:必须使用 ON 子句来指定连结条件.

在进行内连结时 ON 子句是必不可少的(大家可以试试去掉上述查询的 ON 子句后会有什么结果).

ON 子句是专门用来指定连结条件的, 我们在上述查询的 ON 之后指定两张表连结所使用的列以及比较条件, 基本上, 它能起到与 WHERE 相同的筛选作用, 我们会在本章的结尾部分进一步探讨这个话题.

要点三: SELECT 子句中的列最好按照 表名.列名 的格式来使用.

当两张表的列除了用于关联的列之外, 没有名称相同的列的时候, 也可以不写表名, 但表名使得我们能够在今后的任何时间阅读查询代码的时候, 都能马上看出每一列来自于哪张表, 能够节省我们很多时间.

但是, 如果两张表有其他名称相同的列, 则必须使用上述格式来选择列名, 否则查询语句会报错.

我们回到上述查询所回答的问题. 通过观察上述查询的结果, 我们发现, 这个结果离我们的目标: 找出东京商店的衣服类商品的基础信息已经很接近了. 接下来,我们只需要把这个查询结果作为一张表, 给它增加一个 WHERE 子句来指定筛选条件.

2.1.2 结合 WHERE 子句使用内连结

如果需要在使用内连结的时候同时使用 WHERE 子句对检索结果进行筛选, 则需要把 WHERE 子句写在 ON 子句的后边.

例如, 对于上述查询问题, 我们可以在前一步查询的基础上, 增加 WHERE 条件.

增加 WHERE 子句的方式有好几种,我们先从最简单的说起.

第一种增加 WEHRE 子句的方式, 就是把上述查询作为子查询, 用括号封装起来, 然后在外层查询增加筛选条件.

SELECT *FROM (-- 第一步查询的结果SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.product_type,P.sale_price,SP.quantityFROMshopproduct AS SPINNER JOINproduct AS PON SP.product_id = P.product_id) AS STEP1WHERE shop_name = '东京'AND product_type = '衣服' ;

在这里插入图片描述
还记得我们学习子查询时的认识吗? 子查询的结果其实也是一张表,只不过是一张虚拟的表, 它并不真实存在于数据库中, 只是数据库中其他表经过筛选,聚合等查询操作后得到的一个"视图".
这种写法能很清晰地分辨出每一个操作步骤, 在我们还不十分熟悉 SQL 查询每一个子句的执行顺序的时候可以帮到我们.

但实际上, 如果我们熟知 WHERE 子句将在 FROM 子句之后执行, 也就是说, 在做完 INNER JOIN … ON 得到一个新表后, 才会执行 WHERE 子句, 那么就得到标准的写法:

SELECT  SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.product_type,P.sale_price,SP.quantityFROMshopproduct AS SPINNER JOINproduct AS PON SP.product_id = P.product_idWHERE SP.shop_name = '东京'AND P.product_type = '衣服' ;

在这里插入图片描述

我们首先给出上述查询的执行顺序:
FROM 子句->WHERE 子句->SELECT 子句

也就是说, 两张表是先按照连结列进行了连结, 得到了一张新表, 然后 WHERE 子句对这张新表的行按照两个条件进行了筛选, 最后, SELECT 子句选出了那些我们需要的列.

此外, 一种不是很常见的做法是,还可以将 WHERE 子句中的条件直接添加在 ON 子句中, 这时候 ON 子句后最好用括号将连结条件和筛选条件括起来.

SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.product_type,P.sale_price,SP.quantityFROM shopproduct AS SPINNER JOIN product AS PON (SP.product_id = P.product_idAND SP.shop_name = '东京'AND P.product_type = '衣服') ;

在这里插入图片描述
但上述这种把筛选条件和连结条件都放在 ON 子句的写法, 不是太容易阅读, 不建议大家使用.
另外, 先连结再筛选的标准写法的执行顺序是, 两张完整的表做了连结之后再做筛选,如果要连结多张表, 或者需要做的筛选比较复杂时, 在写 SQL 查询时会感觉比较吃力. 在结合 WHERE 子句使用内连结的时候, 我们也可以更改任务顺序, 并采用任务分解的方法,先分别在两个表使用 WHERE 进行筛选,然后把上述两个子查询连结起来.

SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.product_type,P.sale_price,SP.quantityFROM (-- 子查询 1:从shopproduct 表筛选出东京商店的信息SELECT *FROM shopproductWHERE shop_name = '东京' ) AS SPINNER JOIN -- 子查询 2:从 product 表筛选出衣服类商品的信息(SELECT *FROM productWHERE product_type = '衣服') AS PON SP.product_id = P.product_id;

在这里插入图片描述
先分别在两张表里做筛选, 把复杂的筛选条件按表分拆, 然后把筛选结果(作为表)连接起来, 避免了写复杂的筛选条件, 因此这种看似复杂的写法, 实际上整体的逻辑反而非常清晰. 在写查询的过程中, 首先要按照最便于自己理解的方式来写, 先把问题解决了, 再思考优化的问题.
练习题:
找出每个商店里的衣服类商品的名称及价格等信息. 希望得到如下结果:

SELECT SP.*,P.*FROM shopproduct AS SPINNER JOIN product AS PON (SP.product_id = P.product_id AND P.product_type = '衣服');
SELECT  SP.shop_id, SP.shop_name, SP.product_id,P.product_name, P.product_type, P.purchase_priceFROM shopproduct AS SP 
INNER JOIN -- 从 product 表找出衣服类商品的信息(SELECT product_id, product_name, product_type, purchase_priceFROM product	WHERE product_type = '衣服')AS P ON SP.product_id = P.product_id;

上述第二种写法虽然包含了子查询, 并且代码行数更多, 但由于每一层的目的很明确, 更适于阅读, 并且在外连结的情形下, 还能避免错误使用 WHERE 子句导致外连结失效的问题, 相关示例见后文中的"结合 WHERE 子句使用外连结"章节.

练习题:

分别使用连结两个子查询和不使用子查询的方式, 找出东京商店里, 售价低于 2000 的商品信息,希望得到如下结果.

SELECT  SP.shop_id, SP.shop_name, SP.product_id,P.product_name, P.product_type, P.purchase_priceFROM shopproduct AS SP 
INNER JOIN -- 从 product 表找出衣服类商品的信息(SELECT product_id, product_name, product_type, purchase_priceFROM product	WHERE sale_price < 2000)AS P ON SP.product_id = P.product_idWHERE shop_name = '东京';
SELECT  SP.*,P.*FROM shopproduct AS SP 
INNER JOIN product AS PON (SP.product_id = P.product_idAND SP.shop_name = '东京'AND P.sale_price<2000);

在这里插入图片描述

2.1.3结合 GROUP BY 子句使用内连结

结合 GROUP BY 子句使用内连结, 需要根据分组列位于哪个表区别对待.

最简单的情形, 是在内连结之前就使用 GROUP BY 子句.

但是如果分组列和被聚合的列不在同一张表, 且二者都未被用于连结两张表, 则只能先连结, 再聚合.
练习题:

每个商店中, 售价最高的商品的售价分别是多少?

SELECT SP.shop_id,SP.shop_name,MAX(P.sale_price) AS max_priceFROM shopproduct AS SPINNER JOIN product AS PON SP.product_id = P.product_idGROUP BY SP.shop_id

**思考题:**上述查询得到了每个商品售价最高的商品, 但并不知道售价最高的商品是哪一个.如何获取每个商店里售价最高的商品的名称和售价?

注: 这道题的一个简易的方式是使用下一章的窗口函数. 当然, 也可以使用其他我们已经学过的知识来实现, 例如,
在找出每个商店售价最高商品的价格后, 使用这个价格再与product 列进行连结, 但这种做法在价格不唯一时会出现问题.

2.1.4自连结(SELF JOIN)

之前的内连结, 连结的都是不一样的两个表. 但实际上一张表也可以与自身作连结, 这种连接称之为自连结. 需要注意, 自连结并不是区分于内连结和外连结的第三种连结, 自连结可以是外连结也可以是内连结, 它是不同于内连结外连结的另一个连结的分类方法.

2.1.5内连结与关联子查询

回忆第五章第三节关联子查询中的问题: 找出每个商品种类当中售价高于该类商品的平均售价的商品.当时我们是使用关联子查询来实现的.

SELECT product_type, product_name, sale_priceFROM product AS P1WHERE sale_price > (SELECT AVG(sale_price)FROM product AS P2WHERE P1.product_type = P2.product_typeGROUP BY product_type);

使用内连结同样可以解决这个问题:
首先, 使用 GROUP BY 按商品类别分类计算每类商品的平均价格.

SELECT  product_type,AVG(sale_price) AS avg_price FROM product GROUP BY product_type;

接下来, 将上述查询与表 product 按照 product_type (商品种类)进行内连结.

SELECT  P1.product_id,P1.product_name,P1.product_type,P1.sale_price,P2.avg_priceFROM product AS P1 INNER JOIN (SELECT product_type,AVG(sale_price) AS avg_price FROM product GROUP BY product_type) AS P2 ON P1.product_type = P2.product_type;

最后, 增加 WHERE 子句, 找出那些售价高于该类商品平均价格的商品.完整的代码如下:

SELECT  P1.product_id,P1.product_name,P1.product_type,P1.sale_price,P2.avg_priceFROM product AS P1INNER JOIN (SELECT product_type,AVG(sale_price) AS avg_price FROM product GROUP BY product_type) AS P2 ON P1.product_type = P2.product_typeWHERE P1.sale_price > P2.avg_price;

在这里插入图片描述
仅仅从代码量上来看, 上述方法似乎比关联子查询更加复杂, 但这并不意味着这些代码更难理解. 通过上述分析, 很容易发现上述代码的逻辑实际上更符合我们的思路, 因此尽管看起来复杂, 但思路实际上更加清晰.
作为对比, 试分析如下代码:

SELECT  P1.product_id,P1.product_name,P1.product_type,P1.sale_price,AVG(P2.sale_price) AS avg_priceFROM product AS P1INNER JOIN product AS P2ON P1.product_type=P2.product_typeWHERE P1.sale_price > P2.sale_priceGROUP BY P1.product_id,P1.product_name,P1.product_type,P1.sale_price,P2.product_type

在这里插入图片描述

虽然去掉了子查询,查询语句的层次更少, 而且代码行数似乎更少, 但实际上这个方法可能更加难以写出来. 在实践中, 一定要按照易于让自己理解的思路去分层次写代码, 而不要花费很长世间写出一个效率可能更高但自己和他人理解起来难度更高的代码.

2.1.6自然连结(NATURAL JOIN)

自然连结并不是区别于内连结和外连结的第三种连结, 它其实是内连结的一种特例–当两个表进行自然连结时, 会按照两个表中都包含的列名来进行等值内连结, 此时无需使用 ON 来指定连接条件.

SELECT *  FROM shopproduct NATURAL JOIN product

在这里插入图片描述
练习题:
试写出与上述自然连结等价的内连结.

SELECT  SP.product_id,SP.shop_id,SP.shop_name,SP.quantity,P.product_name,P.product_type,P.sale_price,P.purchase_price,P.regist_date  FROM shopproduct AS SP INNER JOIN product AS P ON SP.product_id = P.product_id

在这里插入图片描述
使用自然连结还可以求出两张表或子查询的公共部分, 例如教材中 7-1 选取表中公共部分–INTERSECT 一节中的问题: 求表 product 和表 product2 中的公共部分, 也可以用自然连结来实现:

SELECT * FROM product NATURAL JOIN product2

在这里插入图片描述
这个结果和书上给的结果并不一致, 少了运动 T 恤, 这是由于运动 T 恤的 regist_date 字段为空, 在进行自然连结时, 来自于 product 和 product2 的运动 T 恤这一行数据在进行比较时, 实际上是在逐字段进行等值连结, 回忆我们在 6.2ISNULL,IS NOT NULL 这一节学到的缺失值的比较方法就可得知, 两个缺失值用等号进行比较, 结果不为真. 而连结只会返回对连结条件返回为真的那些行.

如果我们将查询语句进行修改:

SELECT * FROM (SELECT product_id, product_nameFROM product ) AS A 
NATURAL JOIN (SELECT product_id, product_name FROM product2) AS B;

那就可以得到正确的结果了:
在这里插入图片描述

2.1.7使用连结求交集

我们在上一节表的加减法里知道, MySQL 8.0 里没有交集运算, 我们当时是通过并集和差集来实现求交集的. 现在学了连结, 让我们试试使用连结来实现求交集的运算.

练习题: 使用内连结求product 表和product2 表的交集.

SELECT P1.*FROM product AS P1INNER JOIN product2 AS P2ON (P1.product_id  = P2.product_idAND P1.product_name = P2.product_nameAND P1.product_type = P2.product_typeAND P1.sale_price   = P2.sale_priceAND P1.regist_date  = P2.regist_date)

得到如下结果

在这里插入图片描述
注意上述结果和 P230 的结果并不一致–少了 product_id='0001’这一行, 观察源表数据可发现, 少的这行数据的 regist_date 为缺失值, 回忆第六章讲到的 IS NULL 谓词, 我们得知, 这是由于缺失值是不能用等号进行比较导致的.

如果我们仅仅用 product_id 来进行连结:

SELECT P1.*FROM product AS P1INNER JOIN product2 AS P2ON P1.product_id = P2.product_id

查询结果:

在这里插入图片描述
这次就一致了.

2.2 外连结(OUTER JOIN)

内连结会丢弃两张表中不满足 ON 条件的行,和内连结相对的就是外连结. 外连结会根据外连结的种类有选择地保留无法匹配到的行.

按照保留的行位于哪张表,外连结有三种形式: 左连结, 右连结和全外连结.

左连结会保存左表中无法按照 ON 子句匹配到的行, 此时对应右表的行均为缺失值; 右连结则会保存右表中无法按照 ON 子句匹配到的行, 此时对应左表的行均为缺失值; 而全外连结则会同时保存两个表中无法按照 ON子句匹配到的行, 相应的另一张表中的行用缺失值填充.

三种外连结的对应语法分别为:

-- 左连结     
FROM <tb_1> LEFT  OUTER JOIN <tb_2> ON <condition(s)>
-- 右连结     
FROM <tb_1> RIGHT OUTER JOIN <tb_2> ON <condition(s)>
-- 全外连结
FROM <tb_1> FULL  OUTER JOIN <tb_2> ON <condition(s)>

2.2.1 左连结与右连接

由于连结时可以交换左表和右表的位置, 因此左连结和右连结并没有本质区别.接下来我们先以左连结为例进行学习. 所有的内容在调换两个表的前后位置, 并将左连结改为右连结之后, 都能得到相同的结果. 稍后再介绍全外连结的概念.

2.2.2 使用左连结从两个表获取信息

如果你仔细观察过将shopproduct 和product 进行内连结前后的结果的话, 你就会发现,product 表中有两种商品并未在内连结的结果里, 就是说, 这两种商品并未在任何商店有售(这通常意味着比较重要的业务信息, 例如, 这两种商品在所有商店都处于缺货状态, 需要及时补货). 现在, 让我们先把之前内连结的 SELECT 语句转换为左连结试试看吧.

练习题: 统计每种商品分别在哪些商店有售, 需要包括那些在每个商店都没货的商品.

使用左连结的代码如下(注意区别于书上的右连结):

SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.sale_priceFROM product AS PLEFT OUTER JOIN shopproduct AS SPON SP.product_id = P.product_id;

上述查询得到的检索结果如下(由于并未使用 ORDER BY 子句指定顺序,你执行上述代码得到的结果可能顺序与下图不同):
在这里插入图片描述
我们观察上述结果可以发现, 有两种商品: 高压锅和圆珠笔, 在所有商店都没有销售. 由于我们在 SELECT 子句选择列的显示顺序以及未对结果进行排序的原因, 这个事实需要你仔细地进行观察.

  • 外连结要点 1: 选取出单张表中全部的信息

与内连结的结果相比,不同点显而易见,那就是结果的行数不一样.内连结的结果中有 13 条记录,而外连结的结果中有 15 条记录,增加的 2 条记录到底是什么呢?这正是外连结的关键点. 多出的 2 条记录是高压锅和圆珠笔,这 2 条记录在shopproduct 表中并不存在,也就是说,这 2 种商品在任何商店中都没有销售.由于内连结只能选取出同时存在于两张表中的数据,因此只在product 表中存在的 2 种商品并没有出现在结果之中.相反,对于外连结来说,只要数据存在于某一张表当中,就能够读取出来.在实际的业务中,例如想要生成固定行数的单据时,就需要使用外连结.如果使用内连结的话,根据 SELECT 语句执行时商店库存状况的不同,结果的行数也会发生改变,生成的单据的版式也会受到影响,而使用外连结能够得到固定行数的结果.虽说如此,那些表中不存在的信息我们还是无法得到,结果中高压锅和圆珠笔的商店编号和商店名称都是 NULL (具体信息大家都不知道,真是无可奈何).外连结名称的由来也跟 NULL 有关,即“结果中包含原表中不存在(在原表之外)的信息”.相反,只包含表内信息的连结也就被称为内连结了.

  • 外连结要点 2:使用 LEFT、RIGHT 来指定主表.

外连结还有一点非常重要,那就是要把哪张表作为主表.最终的结果中会包含主表内所有的数据.指定主表的关键字是 LEFT 和 RIGHT.顾名思义,使用 LEFT 时 FROM 子句中写在左侧的表是主表,使用 RIGHT 时右侧的表是主表.代码清单 7-11 中使用了 RIGHT ,因此,右侧的表,也就是product 表是主表.我们还可以像代码清单 7-12 这样进行改写,意思完全相同.这样你可能会困惑,到底应该使用 LEFT 还是 RIGHT?其实它们的功能没有任何区别,使用哪一个都可以.通常使用 LEFT 的情况会多一些,但也并没有非使用这个不可的理由,使用 RIGHT 也没有问题.

通过交换两个表的顺序, 同时将 LEFT 更换为 RIGHT(如果原先是 RIGHT,则更换为 LEFT), 两种方式会到完全相同的结果.

2.2.3结合 WHERE 子句使用左连结

上一小节我们学到了外连结的基础用法, 并且在上一节也学习了结合WHERE子句使用内连结的方法, 但在结合WHERE子句使用外连结时, 由于外连结的结果很可能与内连结的结果不一样, 会包含那些主表中无法匹配到的行, 并用缺失值填写另一表中的列, 由于这些行的存在, 因此在外连结时使用WHERE子句, 情况会有些不一样. 我们来看一个例子:

练习题:

使用外连结从shopproduct表和product表中找出那些在某个商店库存少于50的商品及对应的商店.希望得到如下结果.

在这里插入图片描述
注意高压锅和圆珠笔两种商品在所有商店都无货, 所以也应该包括在内.

按照"结合WHERE子句使用内连结"的思路, 我们很自然会写出如下代码

SELECT P.product_id,P.product_name,P.sale_price,SP.shop_id,SP.shop_name,SP.quantityFROM product AS PLEFT OUTER JOIN shopproduct AS SPON SP.product_id = P.product_idWHERE quantity< 50

然而不幸的是, 得到的却是如下的结果:

在这里插入图片描述
观察发现,返回结果缺少了在所有商店都无货的高压锅和圆珠笔。聪明的你可能很容易想到,在WHERE过滤条件中增加OR``quantity IS NULL的判断条件,便可以得到预期结果。然而在实际环境中,由于数据量大且数据质量并非像我们设想的那样"干净",我们并不能容易地意识到缺失值等问题数据的存在,因此,还是让我们想一下如何改写我们的查询以使得它能够适应更复杂的真实数据的情形吧。

联系到我们已经掌握了的SQL查询的执行顺序(FROM->WHERE->SELECT),我们发现, 问题可能出在筛选条件上, 因为在进行完外连结后才会执行WHERE子句, 因此那些主表中无法被匹配到的行就被WHERE条件筛选掉了。

明白了这一点, 我们就可以试着把WHERE子句挪到外连结之前进行: 先写个子查询,用来从shopproduct表中筛选quantity<50的商品, 然后再把这个子查询和主表连结起来。

我们把上述思路写成SQL查询语句:

SELECT P.product_id,P.product_name,P.sale_price,SP.shop_id,SP.shop_name,SP.quantity FROMproduct AS PLEFT OUTER JOIN-- 先筛选quantity<50的商品(SELECT *FROMshopproductWHERE quantity < 50 ) AS SPON SP.product_id = P.product_id

得到的结果如下:
在这里插入图片描述

2.2.4在 MySQL 中实现全外连结

有了对左连结和右连结的了解, 就不难理解全外连结的含义了. 全外连结本质上就是对左表和右表的所有行都予以保留, 能用 ON 关联到的就把左表和右表的内容在一行内显示, 不能被关联到的就分别显示, 然后把多余的列用缺失值填充。

遗憾的是, MySQL8.0 目前还不支持全外连结, 不过我们可以对左连结和右连结的结果进行 UNION 来实现全外连结。

2.3多表连结

通常连结只涉及 2 张表,但有时也会出现必须同时连结 3 张以上的表的情况, 原则上连结表的数量并没有限制。

2.3.1 多表进行内连结

首先创建一个用于三表连结的表 Inventoryproduct.首先我们创建一张用来管理库存商品的表, 假设商品都保存在 P001 和 P002 这 2 个仓库之中.
在这里插入图片描述
建表语句如下:

CREATE TABLE Inventoryproduct
( inventory_id       CHAR(4) NOT NULL,
product_id         CHAR(4) NOT NULL,
inventory_quantity INTEGER NOT NULL,
PRIMARY KEY (inventory_id, product_id));

然后插入一些数据:

-- DML:插入数据
START TRANSACTION;
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P001', '0001', 0);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P001', '0002', 120);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P001', '0003', 200);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P001', '0004', 3);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P001', '0005', 0);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P001', '0006', 99);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P001', '0007', 999);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P001', '0008', 200);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P002', '0001', 10);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P002', '0002', 25);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P002', '0003', 34);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P002', '0004', 19);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P002', '0005', 99);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P002', '0006', 0);
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P002', '0007', 0 );
INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity)
VALUES ('P002', '0008', 18);
COMMIT;

接下来, 我们根据上表及shopproduct 表和product 表, 使用内连接找出每个商店都有那些商品, 每种商品的库存总量分别是多少.

SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.sale_price,IP.inventory_quantityFROM shopproduct AS SPINNER JOIN product AS PON SP.product_id = P.product_idINNER JOIN Inventoryproduct AS IPON SP.product_id = IP.product_idWHERE IP.inventory_id = 'P001';

得到如下结果

在这里插入图片描述
我们可以看到, 连结第三张表的时候, 也是通过 ON 子句指定连结条件(这里使用最基础的等号将作为连结条件的product 表和shopproduct 表中的商品编号 product _id 连结了起来), 由于product 表和shopproduct 表已经进行了连结,因此就无需再对product 表和 Inventoryproduct 表进行连结了(虽然也可以进行连结,但结果并不会发生改变, 因为本质上并没有增加新的限制条件).

即使想要把连结的表增加到 4 张、5 张……使用 INNER JOIN 进行添加的方式也是完全相同的.

2.3.2多表进行外连结

正如之前所学发现的, 外连结一般能比内连结有更多的行, 从而能够比内连结给出更多关于主表的信息, 多表连结的时候使用外连结也有同样的作用.

例如,

SELECT P.product_id,P.product_name,P.sale_price,SP.shop_id,SP.shop_name,IP.inventory_quantityFROM product AS PLEFT OUTER JOIN shopproduct AS SP
ON SP.product_id = P.product_id
LEFT OUTER JOIN Inventoryproduct AS IP
ON SP.product_id = IP.product_id

查询结果

在这里插入图片描述

2.4 ON 子句进阶–非等值连结

在刚开始介绍连结的时候, 书上提到过, 除了使用相等判断的等值连结, 也可以使用比较运算符来进行连接. 实际上, 包括比较运算符(<,<=,>,>=, BETWEEN)和谓词运算(LIKE, IN, NOT 等等)在内的所有的逻辑运算都可以放在 ON 子句内作为连结条件.

2.4.1非等值自左连结(SELF JOIN)

使用非等值自左连结实现排名。

练习题:

希望对 product 表中的商品按照售价赋予排名. 一个从集合论出发,使用自左连结的思路是, 对每一种商品,找出售价不低于它的所有商品, 然后对售价不低于它的商品使用 COUNT 函数计数. 例如, 对于价格最高的商品,

SELECT  product_id,product_name,sale_price,COUNT(p2_id) AS rank_idFROM (-- 使用自左连结对每种商品找出价格不低于它的商品SELECT P1.product_id,P1.product_name,P1.sale_price,P2.product_id AS P2_id,P2.product_name AS P2_name,P2.sale_price AS P2_price FROM product AS P1 LEFT OUTER JOIN product AS P2 ON P1.sale_price <= P2.sale_price ) AS XGROUP BY product_id, product_name, sale_priceORDER BY rank_id; 

在这里插入图片描述
注 1: COUNT 函数的参数是列名时, 会忽略该列中的缺失值, 参数为 * 时则不忽略缺失值.
注 2: 上述排名方案存在一些问题–如果两个商品的价格相等, 则会导致两个商品的排名错误, 例如, 叉子和打孔器的排名应该都是第六, 但上述查询导致二者排名都是第七. 试修改上述查询使得二者的排名均为第六.
注 3: 实际上, 进行排名有专门的函数, 这是 MySQL 8.0 新增加的窗口函数中的一种(窗口函数将在下一章学习), 但在较低版本的 MySQL 中只能使用上述自左连结的思路.

使用非等值自左连结进行累计求和:

练习题:

请按照商品的售价从低到高,对售价进行累计求和[注:这个案例缺少实际意义, 并且由于有两种商品价格相同导致了不必要的复杂度, 但示例数据库的表结构比较简单, 暂时未想出有实际意义的例题]

首先, 按照题意, 对每种商品使用自左连结, 找出比该商品售价价格更低或相等的商品

SELECT  P1.product_id,P1.product_name,P1.sale_price,P2.product_id AS P2_id,P2.product_name AS P2_name,P2.sale_price AS P2_price FROM product AS P1 LEFT OUTER JOIN product AS P2 ON P1.sale_price >= P2.sale_priceORDER BY P1.sale_price,P1.product_id	

查看查询结果

在这里插入图片描述
看起来似乎没什么问题.

下一步, 按照 P1.product_Id 分组,对 P2_price 求和:

SELECT  product_id,product_name,sale_price,SUM(P2_price) AS cum_price FROM (SELECT  P1.product_id,P1.product_name,P1.sale_price,P2.product_id AS P2_id,P2.product_name AS P2_name,P2.sale_price AS P2_price FROM product AS P1 LEFT OUTER JOIN product AS P2 ON P1.sale_price >= P2.sale_priceORDER BY P1.sale_price,P1.product_id ) AS XGROUP BY product_id, product_name, sale_priceORDER BY sale_price,product_id;

得到的查询结果为:

在这里插入图片描述
观察上述查询结果发现, 由于有两种商品的售价相同, 在使用 >= 进行连结时, 导致了累计求和错误, 这是由于这两种商品售价相同导致的. 因此实际上之前是不应该单独只用 >= 作为连结条件的. 考察我们建立自左连结的本意, 是要找出满足:1.比该商品售价更低的, 或者是 2.该种商品自身,以及 3.如果 A 和 B 两种商品售价相等,则建立连结时, 如果 P1.A 和 P2.A,P2.B 建立了连接, 则 P1.B 不再和 P2.A 建立连结, 因此根据上述约束条件, 利用 ID 的有序性, 进一步将上述查询改写为:

SELECT	product_id, product_name, sale_price,SUM(P2_price) AS cum_price FROM(SELECT  P1.product_id, P1.product_name, P1.sale_price,P2.product_id AS P2_id,P2.product_name AS P2_name,P2.sale_price AS P2_price FROM product AS P1 LEFT OUTER JOIN product AS P2 ON ((P1.sale_price > P2.sale_price)OR (P1.sale_price = P2.sale_price AND P1.product_id<=P2.product_id))ORDER BY P1.sale_price,P1.product_id) AS XGROUP BY product_id, product_name, sale_priceORDER BY sale_price,cum_price;

在这里插入图片描述
这次结果就正确了.

2.5 交叉连结—— CROSS JOIN(笛卡尔积)

之前的无论是外连结内连结, 一个共同的必备条件就是连结条件–ON 子句, 用来指定连结的条件. 如果你试过不使用这个连结条件的连结查询, 你可能已经发现, 结果会有很多行. 在连结去掉 ON 子句, 就是所谓的交叉连结(CROSS JOIN), 交叉连结又叫笛卡尔积, 后者是一个数学术语. 两个集合做笛卡尔积, 就是使用集合 A 中的每一个元素与集合 B 中的每一个元素组成一个有序的组合. 数据库表(或者子查询)的并,交和差都是在纵向上对表进行扩张或筛选限制等运算的, 这要求表的列数及对应位置的列的数据类型"相容", 因此这些运算并不会增加新的列, 而交叉连接(笛卡尔积)则是在横向上对表进行扩张, 即增加新的列, 这一点和连结的功能是一致的. 但因为没有了ON子句的限制, 会对左表和右表的每一行进行组合, 这经常会导致很多无意义的行出现在检索结果中. 当然, 在某些查询需求中, 交叉连结也有一些用处.

交叉连结的语法有如下几种形式:

-- 1.使用关键字 CROSS JOIN 显式地进行交叉连结
SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.sale_priceFROM shopproduct AS SPCROSS JOIN product AS P;
-- 2.使用逗号分隔两个表,并省略 ON 子句
SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.sale_priceFROM shopproduct AS SP ,product AS P;

在这里插入图片描述
请大家试着执行一下以上语句.
可能大家会惊讶于结果的行数, 但我们还是先来介绍一下语法结构吧.对满足相同规则的表进行交叉连结的集合运算符是 CROSS JOIN (笛卡儿积).进行交叉连结时无法使用内连结和外连结中所使用的ON 子句,这是因为交叉连结是对两张表中的全部记录进行交叉组合,因此结果中的记录数通常是两张表中行数的乘积.本例中,因为shopproduct 表存在 13 条记录,product 表存在 8 条记录,所以结果中就包含了 13 × 8 = 104 条记录.

可能这时会有读者想起前面我们提到过集合运算中的乘法会在本节中进行详细学习,这就是上面介绍的交叉连结.内连结是交叉连结的一部分,“内”也可以理解为“包含在交叉连结结果中的部分”.相反,外连结的“外”可以理解为“交叉连结结果之外的部分”.

交叉连结没有应用到实际业务之中的原因有两个.一是其结果没有实用价值,二是由于其结果行数太多,需要花费大量的运算时间和高性能设备的支持.

2.5.1[扩展阅读]连结与笛卡儿积的关系

考察笛卡儿积和连结, 不难发现, 笛卡儿积可以视作一种特殊的连结(事实上笛卡儿积的语法也可以写作 CROSS JOIN), 这种连结的 ON 子句是一个恒为真的谓词.

反过来思考, 在对笛卡儿积进行适当的限制之后, 也就得到了内连结和外连结.

例如, 对于 shopproduct 表和 product 表, 首先建立笛卡尔乘积:

SELECT SP.*, P.*FROM shopproduct AS SP CROSS JOIN product AS P;

在这里插入图片描述
然后对上述笛卡尔乘积增加筛选条件 SP.product_id=P.product_id, 就得到了和内连结一致的结果:

SELECT SP.*, P.*FROM shopproduct AS SP CROSS JOIN product AS PWHERE SP.product_id = P.product_id;

查询结果如下:
在这里插入图片描述
实际上, 正如书中所说, 上述写法中, 将 CROSS JOIN 改为逗号后, 正是内连结的旧式写法, 但在 ANSI 和 ISO 的 SQL-92 标准中, 已经将使用 INNER JION …ON… 的写法规定为标准写法, 因此极力推荐大家在平时写 SQL 查询时, 使用规范写法.

2.6 连结的特定语法和过时语法

在笛卡尔积的基础上, 我们增加一个 WHERE 子句, 将之前的连结条件作为筛选条件加进去, 我们会发现, 得到的结果恰好是直接使用内连接的结果.

试执行以下查询, 并将查询结果与内连结一节第一个例子的结果做对比.

SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.sale_priceFROM shopproduct AS SPCROSS JOIN product AS PWHERE SP.product_id = P.product_id;

在这里插入图片描述
我们发现, 这两个语句得到的结果是相同的.
之前我们学习的内连结和外连结的语法都符合标准 SQL 的规定,可以在所有 DBMS 中执行,因此大家可以放心使用. 但是如果大家之后从事系统开发工作, 或者阅读遗留SQL 查询语句的话,一定会碰到需要阅读他人写的代码并进行维护的情况,而那些使用特定和过时语法的程序就会成为我们的麻烦.

SQL 是一门特定语法及过时语法非常多的语言,虽然之前本书中也多次提及,但连结是其中特定语法的部分,现在还有不少年长的程序员和系统工程师仍在使用这些特定的语法.例如,将本节最初介绍的内连结的 SELECT 语句替换为过时语法的结果如下所示.

使用过时语法的内连结(结果与代码清单 7-9 相同)

SELECT SP.shop_id,SP.shop_name,SP.product_id,P.product_name,P.sale_priceFROM shopproduct SP,product PWHERE SP.product_id = P.product_idAND SP.shop_id = '000A';

在这里插入图片描述
这样的书写方式所得到的结果与标准语法完全相同,并且这样的语法可以在所有的 DBMS 中执行,并不能算是特定的语法,只是过时了而已.
但是,由于这样的语法不仅过时,而且还存在很多其他的问题,因此不推荐大家使用,理由主要有以下三点:

第一,使用这样的语法无法马上判断出到底是内连结还是外连结(又或者是其他种类的连结).

第二,由于连结条件都写在 WHERE 子句之中,因此无法在短时间内分辨出哪部分是连结条件,哪部分是用来选取记录的限制条件.

第三,我们不知道这样的语法到底还能使用多久.每个 DBMS 的开发者都会考虑放弃过时的语法,转而支持新的语法.虽然并不是马上就不能使用了,但那一天总会到来的.

虽然这么说,但是现在使用这些过时语法编写的程序还有很多,到目前为止还都能正常执行.我想大家很可能会碰到这样的代码,因此还是希望大家能够了解这些知识.

三、练习题

3.1 练习题1

找出 product 和 product2 中售价高于 500 的商品的基本信息。


SELECT *
FROM product
WHERE sale_price > 500UNIONSELECT *
FROM product2
WHERE sale_price > 500

在这里插入图片描述

3.2 练习题2

借助对称差的实现方式, 求product和product2的交集。


SELECT *FROM productWHERE product_id IN (SELECT product_id FROM product2)UNIONSELECT *FROM product2WHERE product_id IN (SELECT product_id FROM product)

在这里插入图片描述

3.3 练习题3

每类商品中售价最高的商品都在哪些商店有售 ?


SELECT SP.shop_id,SP.shop_name,SP.product_id
FROM shop_product AS SP
WHERE SP.product_id in 
(SELECT p1.product_id FROM product AS p1
INNER JOIN 
(SELECT product_type, MAX(sale_price) AS max_sale_price
FROM product
GROUP BY product_type) AS p2
ON p1.product_type = p2.product_type
AND p1.sale_price = p2.max_sale_price) 

在这里插入图片描述
这里面3类商品中,有3个最大值,查询结果为000300050008这三个ID的商品,但是在shop_product表中,没有对应的商店销售00050008商品,所以结果只有0003商品的在售商店信息。

3.4 练习题4

分别使用内连结和关联子查询每一类商品中售价最高的商品。


  • 内连结
SELECT p1.product_id, p1.product_name, p1.product_type, p1.sale_price, p2.max_sale_price 
FROM product AS p1
INNER JOIN (SELECT product_type, MAX(sale_price) AS max_sale_priceFROM productGROUP BY product_type) AS p2
ON p1.product_type = p2.product_type
AND p1.sale_price = p2.max_sale_price;

在这里插入图片描述

  • 关联子查询
SELECT p1.product_id, p1.product_name, p1.product_type, p1.sale_price
FROM product AS p1
WHERE p1.sale_price = (SELECT MAX(sale_price) AS max_sale_priceFROM product AS p2WHERE p1.product_type = p2.product_typeGROUP BY product_type);

在这里插入图片描述

3.5 练习题5

用关联子查询实现:在product表中,取出 product_id, produc_name, slae_price, 并按照商品的售价从低到高进行排序、对售价进行累计求和。


select product_id, product_name, sale_price, (select sum(sale_price)from product p2where p2.sale_price <= p1.sale_price) sum
from product p1
order by sale_price;

在这里插入图片描述

四、小结

这一章的内容比较多,并且都是SQL的进阶知识,理解起来不像之前那样容易,我在跟班学习的时候都没有遇到这么多复杂的问题,这一章确实学到了很多很多东西,当然,这一章过一遍肯定是不够的,因为它很重要,等过段时间再回来翻阅这篇博客,还得重新学习~学习的路很长,大家一起加油~!

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. Shiro视频下载,Java安全框架入门实战学习

    Shiro是一个强大且易用的Java平台的开源权限框架&#xff0c;用于身份验证、授权、加解密和会话管理&#xff0c;它使用简单&#xff0c;可以快速、轻松地让任何应用程序获得如下需求的支持&#xff1a; &#xff08;1&#xff09;用户&#xff0c;角色&#xff0c;权限&#x…...

    2024/4/26 15:45:50
  2. Istio系列学习(三)----非侵入的流量治理(1)

    一、Istio流量治理 目标: 以基础设施的方式提供给用户非侵入的流量治理能力,用户只需关注自己的业务逻辑开发,无须关注服务访问管理. 流量治理要解决的问题: 服务的负载均衡 2&#xff09;同一个服务有两个版本在线&#xff0c;将一部分流量切到某个版本上 3&#xff09;服…...

    2024/4/7 4:02:05
  3. 前端案例:我的备忘录(支持事件的增加、删除和修改,代码完整)

    本案例未使用任何框架&#xff0c;均使用 js 原生以及 DOM 操作实现&#xff0c;代码完整&#xff0c;复制即用。 目录 一、案例效果 二、涉及要点 1. 事件监听 2. DOM 节点操作 &#xff08;1&#xff09;常用节点获取方法 &#xff08;2&#xff09;常用节点信息获取方…...

    2024/4/17 15:59:00
  4. Spring Boot 快速上手(6)整合Druid

    Spring Boot 快速上手&#xff08;6&#xff09;整合Druid添加依赖修改配置配置管理面板添加依赖 在mybatis或者mybatis plus 项目基础上改造 <druid.version>1.2.6</druid.version> ... <!-- druid 配置 --> <dependency><groupId>com.alibab…...

    2024/4/17 3:35:23
  5. 个性设置输出台模板

    配置文件更改端口号 #更改项目的端口号 server.port8081配置文件更改Banner 模板网站&#xff1a;https://www.bootschool.net/ascii复制模板&#xff0c;在resources里创建banner.txt文件&#xff0c;将选好的模板粘贴进去/*[*/#include<stdio.h>// …...

    2024/4/7 4:02:02
  6. 可能是最卷的Spring源码系列(十五):事务

    spring中事务流程跟aop基本上是一样的&#xff0c;所以还是安装上篇的套路&#xff0c;先看看事务是如何使用的&#xff0c;再分析源码 事务的使用 本文为了清晰的演示事务&#xff0c;所以不使用mybatis&#xff0c;很多时候我们用了这些成熟的框架之后&#xff0c;根本无法…...

    2024/4/14 18:05:04
  7. Python是不是被严重高估了?

    第一派便是传统java党&#xff0c;除了C其他语言都瞧不起&#xff1b;第二派就是吃到过py的甜头&#xff0c;大底上持中立态度&#xff1b;而第三派便是py吃到底&#xff0c;除了搞数据的怕就是搞教育的了&#xff08;败坏py名声的主要部分人&#xff09;。 首先&#xff0c;很…...

    2024/4/17 11:21:31
  8. Linux篇 NXP IMX-8MQEVK 用Yoctor搭建环境

    因为工作需要&#xff0c;用了Linux来开发新产品&#xff0c;然后现在要学习搭建镜像。并且随手记录遇到的一些问题和如何解决。 开发板&#xff1a;NXP imx8mqevk 开发平台&#xff1a;VM Ubuntu&#xff1a;18.04.3LST 工具&#xff1a;Yoctor 指导&#xff1a;i.MX Yoc…...

    2024/4/20 5:50:32
  9. 【Python之pymysql库学习】7.数据表查询操作(保姆级图文+实现代码)

    目录实现效果实现思路实现代码总结欢迎关注 『Python之pymysql库学习』 系列&#xff0c;持续更新中 欢迎关注 『Python之pymysql库学习』 系列&#xff0c;持续更新中 实现效果 实现思路 dbpymysql.connect(host‘localhost’,user‘root’,password‘root’,database‘python…...

    2024/4/7 4:01:59
  10. 面试时,你应该知道的5个 SQL 窗口函数

    SQL是数据世界中的通用语言&#xff0c;是数据从业人员最重要的技能之一。许多数据探索、数据操作、管道开发和仪表板创建都可以通过 SQL 完成的。 伟大的数据科学家与优秀的数据科学家的区别在于&#xff0c;伟大的数据科学家可以尽可能多地利用 SQL 的功能来处理数据。要充分…...

    2024/4/27 22:56:24
  11. Linux Shell 实验总结及知识拓展(操作系统)

    关于Shell及其实验操作 Shell命令语言的知识了解 什么是多进程并发 实现多进程并发的步骤 创建文件用来写脚本语言 文件名2.在vim的文本编辑器中编辑脚本文件 文件名.sh3.保存后在终端执行4.尝试不同的代码观察并发执行 知识概念区分 一&#xff1a;线程与进程 1.概念 线程…...

    2024/4/14 18:05:14
  12. 中国微型涡轮机行业市场供需与战略研究报告

    出版商&#xff1a;贝哲斯咨询 获取报告样本&#xff1a; 企业竞争态势 微型涡轮机市场报告涉及的主要国际市场参与者有Ansaldo Energia、Bladon Jets、Brayton Energy、Capstone Turbine、MTT、247solar、Bowman Power、Turbotech、Toyota、Flexenergy等。这些参与者的市场份…...

    2024/4/14 18:05:04
  13. 中国心电图机市场趋势报告、技术动态创新及市场预测

    【出版商】贝哲斯咨询 【免费目录下载】心电图机能将心脏活动时心肌激动产生的生物电信号&#xff08;心电信号&#xff09;自动记录下来&#xff0c;为临床诊断和科研常用的医疗电子仪器。经过50年的发展&#xff0c;心电图机的功能越来越人性化&#xff0c;已经成为临床上一…...

    2024/4/14 18:04:54
  14. 常用命令手册

    背景 记录一些开发中可能使用到的命令&#xff0c;用于自己查阅。 内容 ADB Shell 冷启动&#xff1a; adb shell am start -W com.example.calendar/.MainActivity >> d:\time.txt 退到后台&#xff1a; adb shell input keyevent 3 热启动&#xff1a; adb shell …...

    2024/4/17 0:26:22
  15. Python快速排序板子 分而治之

    目录&#xff1a; 一&#xff1a;个人阅读完《算法图解》快速排序后写的代码 二&#xff1a;参考官方代码及个人总结 一&#xff1a;所谓分而治之&#xff08;divide and conquer&#xff0c;D&C&#xff09;是一种递归式解决方法 工作原理&#xff1a;&#xff08;1&…...

    2024/4/14 18:04:59
  16. Web前端开发规范文档

    规范目的 为提高团队协作效率, 便于后台人员添加功能及前端后期优化维护, 输出高质量的文档, 特制订此文档. 本规范文档一经确认, 前端开发人员必须按本文档规范进行前台页面开发. 本文档如有不对或者不合适的地方请及时提出, 经讨论决定后方可更改. 基本准则 符合web标准, …...

    2024/4/5 5:19:48
  17. 全球及中国硅基合成试剂行业运营格局及供需态势分析报告2022~2028年

    全球及中国硅基合成试剂行业运营格局及供需态势分析报告2022&#xff5e;2028年 1 硅基合成试剂市场概述 1.1 硅基合成试剂行业概述及统计范围 1.2 按照不同产品类型&#xff0c;硅基合成试剂主要可以分为如下几个类别 1.2.1 不同产品类型硅基合成试剂增长趋势2018 VS 2021 VS…...

    2024/4/14 18:05:14
  18. 一周的总结

    这一周我在家开始了学习,在家的学习不如在学校那样舒服,在家里缺少了在校时那种学习的氛围,全靠自己的自律.在这一周里,我去村里当志愿者,在那里我知道了疫情的严重&#xff0c;以及所有人对疫情的高度重视&#xff0c;同时让我看到了疫情工作人员的艰辛。在这么寒冷的冬天里&a…...

    2024/4/14 18:05:09
  19. Android 12 “Bug 连连”:除了一加、三星,谷歌自家手机都被“坑”了

    相较于前面几个大版本&#xff0c;去年 10 月才问世的 Android 12 正式版稍显迟缓&#xff1a;2018 年 8 月 7 日谷歌发布 Android 9 正式版&#xff0c;之后 Android 10 正式版于 2019 年 9 月 3日正式发布&#xff0c;Android 11 同样也是 2020 年 9 月 8 日发布。 但即便晚…...

    2024/4/14 18:04:49
  20. Go 语言实践 - Runtime

    Goroutine 原理 内存分配原理 GC 原理 Channel 原理...

    2024/4/7 4:01:50

最新文章

  1. 华为MRS服务使用记录

    背景&#xff1a;公司的业务需求是使用华为的这一套成品来进行开发&#xff0c;使用中发现&#xff0c;这个产品跟原生的Hadoop的那一套的使用&#xff0c;还是有很大的区别的&#xff0c;现记录一下&#xff0c;避免以后忘了 一、原始代码的下载 下载地址&#xff1a;MRS样例…...

    2024/4/28 5:20:41
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 五一假期来临,各地景区云旅游、慢直播方案设计与平台搭建

    一、行业背景 经文化和旅游部数据中心测算&#xff0c;今年清明节假期3天全国国内旅游出游1.19亿人次&#xff0c;按可比口径较2019年同期增长11.5%&#xff1b;国内游客出游花费539.5亿元&#xff0c;较2019年同期增长12.7%。踏青赏花和户外徒步成为假期的热门出游主题。随着…...

    2024/4/27 8:47:24
  4. C++ //练习 11.14 扩展你在11.2.1节练习(第378页)中编写的孩子姓到名的map,添加一个pair的vector,保存孩子的名和生日。

    C Primer&#xff08;第5版&#xff09; 练习 11.14 练习 11.14 扩展你在11.2.1节练习&#xff08;第378页&#xff09;中编写的孩子姓到名的map&#xff0c;添加一个pair的vector&#xff0c;保存孩子的名和生日。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#x…...

    2024/4/22 21:19:28
  5. 增加网站搜索引擎排名的6个准则

    怎样提高网站排名首页 在竞争激烈的网络世界中&#xff0c;网站的排名对于吸引流量和提升曝光至关重要。登上搜索引擎结果页面的首页&#xff0c;意味着更多的曝光和点击率。以下是一些方法&#xff0c;可以帮助您提高网站在搜索引擎中的排名&#xff0c;让其跻身首页&#xf…...

    2024/4/23 6:25:30
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/26 18:09:39
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/28 3:28:32
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/27 4:00:35
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/27 9:01:45
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/28 1:22:35
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/25 18:39:00
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/27 11:43:08
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/27 8:32:30
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57