五,多表合并

image.png

5.1 多表数据合并 UNION

image.png1、将2张表合并 (不去重复)
SELECT FROM 1班 UNION ALL SELECT FROM 2班;

2、将2张表合并 (去重复)
SELECT FROM 1班 UNION SELECT FROM 2班;

总结:
UNION ALL 不去重 UNION 去重

注意事项:
1、不管是UNION还是UNION ALL,都要求SELECT语句拥有相同的列数,而且字段的排放顺序必须相同。
2、如果两张原始表的顺序不一致,你需要手动在SELECT后面写字段强行把他顺序变成一致。
例如:
SELECT 姓名,语文 FROM 1班 UNION ALL SELECT 姓名,语文 FROM 2班;

3、列的名字或别名,是由第一个Select语句的选择列表决定的。
4、ORDER BY子句,必需放在最后一个Select后面
5、如果你遇到了列不一致的情况,如何处理?
image.png
SELECT 姓名,语文,数学,英语 FROM 1班 UNION ALL SELECT 姓名,语文,NULL,英语 FROM 2班
SELECT 姓名,语文,数学,英语 FROM 1班 UNION ALL SELECT 姓名,语文,‘未考’,英语 FROM 2班

5.2 多表合并

SELECT FROM 1班 UNION ALL
SELECT
FROM 2班 UNION ALL

SELECT * FROM 3班 UNION ALL
………..

注意:被union 或 union all 连接的sql 子句,单个子句中不用写order by ,因为不会有排序的效果。但可以对最终的结果集进行排序;

(select 字段名 from 表1 order by 字段名) union all (select 字段名 from 表2 order by 字段名); //没有排序效果

(select 字段名 from 表1) union all (select 字段名 from 表2) order by 字段名; //有排序效果

六, 连接查询

image.pngimage.png

6.1.1 多表配合使用

例1.将店铺表中的表名Vlookup到销售名中

SELECT 销售表.店号,店铺表.店名,销售表.商品编码,销售表.销售数量
FROM 销售表,店铺
WHERE 店铺表.店号=销售表.店号;
以上语句中,店铺表和销售表两个表名反复出现,使代码书写和阅读都趋于复杂,此时我们可以使用表的别名进行简化。
SELECT a.店号,b.店名,a.商品编码,a.销售数量
FROM 销售表a,店铺表b
WHERE b.店号=a.店号;

也可以写成:【推荐写法】
SELECT a.店号,店名,商品编码,销售数量
FROM 销售表a,店铺表b
WHERE b.店号=a.店号;

image.png
对比上一条的语句,不难发现部分字段名省略了表名,这是因为相关字段名称在连接表中是独一无二的;而‘店号’是店铺表和销售表都存在 的字段名,则必须提供表名,否则系统无法识别字段来源。

凡是表里没有这个字段的时候(你自造的字段)必需用HAVING,不能使用WHERE
凡是字段名在FROM表中是唯一的,字段名前可以省略表名

6.1.2 【不推荐】内部连接 FROM+WHERE 1992年

在语句形式上,连接查询通常有两种实现方式。一种是FROM子句列出所有需要连接的表,然后通过WHERE子句列出筛选条件;另一种是通过关键字JOIN建立 表和表之间的连接,再通过关键字ON指定连接条件。

语法:
SELECT 字段名
FROM 表1,表2
WHERE 表1.字段名=表2.字段名
FROM子句列出需要连接查询的多个表,不同表名之间使用英文逗号间隔,然后WHERE子句指定了筛选的条件,最后SELECT子句指定需要提取字段的名称。
image.pngimage.png

6.1.3 【推荐】内部连接 INNER JOIN+ON 1999年

等于:vlookup的意思
内连接通过关键字INNER JOIN 将多表连接,并通过关键字ON,指定连接条件。内连接又称等同连接,返回连接表所有相匹配的记录,舍弃不匹配的记录。
image.png
⬇️详细代码
image.png
内部联接分类:
【常用】等值连接:在连接条件中使用等于号(=)运算符比较被连接列的列值,其查询结果中列出被连接表中的所有列,包括其中的重复列。
select from 表1 inner join 表2 on *表1.字段名 = 表2.字段名

【不常用】不等值连接:在连接条件使用除等于运算符以外的其它比较运算符比较被连接的列的列值。这些运算符包括 >、>=、<=、<、!>、!<和<>。
概念:在连接条件中使用除等于号之外运算符(>、<、<>、>=、<=、!>和!<)
select from 表1 inner join 表2 on *表1.字段名 <> 表2.字段名

自然连接:在连接条件中使用等于(=)运算符比较被连接列的列值,但它使用选择列表指出查询结果集合中所包括的列,并删除连接表中的重复列。

【常用】等值连接
语法:
SELECT 字段名 FROM 1 INNER JOIN 2 ON 连接条件

例 1:把店名V过来
SELECT 日期,a.店号,店名,商品编码,销售数量
FROM 销售表 a
INNER JOIN 店铺表 b
ON a.店号=b.店号
image.png

【重要】例2:查询店号为1.3.7的店名,销售总数量

SELECT a.店号,店名,SUM(销售数量) AS 销售总量
FROM 销售表 a
INNER JOIN 店铺表 b
ON a.店号=b.店号
WHERE a.店号 in(1,3,7)
GROUP BY 店名 # 这里使用a.店号效果一样
image.png

【重要】例3.将店铺表中的店名Vlookup到销售名中,条件是2020.1.1至1.3

SELECT 日期,a.店号,店名,商品编码,销售数量
FROM 销售表 a
INNER JOIN 店铺表 b
ON b.店号=a.店号
WHERE 日期 BETWEEN ‘2020-01-01’ AND ‘2020-01-03’;
image.png

注意:如果假设有一个店号,在商品表里有,销售表里没有,那么就V不过来,反之,在销售表里有,在商品表里没有,也V不过来,因为取的是同时符合条件 的。条件是什么呀?是:

如果你想成为数据库开发和维护人员注意:a表和b表的店号类型要一致。
分析结果:
1、运算FROM语句将两个表连接在一起,连接条件是两个表店号相等的内容才会连接
2WHETE条件只保留级别日期是2020.1.11.3区间的数据
3SELECT后面是返回的字段名

例4:在例1基础上,再添加条件,只看店铺1.3.7这三家店,商品只看A001和B005这两种商品的销售情况


SELECT 日期,a.店号,店名,商品编码,销售数量
FROM 销售表 a INNER JOIN 店铺表 b ON b.店号=a.店号
WHERE 日期 BETWEEN ‘2020-01-01’ and ‘2020-01-03’ and 商品编码 in(‘A001’,’B005’) and a.店号 in(1,3,7)
image.png

6.1.3.1 【不重要】内部连接 之 自然连接

这不是重点,了解即可,你有可能用不到这些知识
网上有些教程和书籍上讲的不对,他们讲的自连接还是普通的内连接,比如用商品名称去找他的大类,那不还是V过来吗?

自连接: 自己的表和自己的表连接:一张表拆为两张一样的表

image.png6.1.4 【重要】左外连接 LEFT JOIN + ON

左连接,返回左表中的所有行,如果左表中行在右表中没有匹配行,则结果中右表中的列返回空值。
image.png
image.png
例:我想将销售表按商品编码,将商品里的其它信息都V过来
SELECT a.*,商品名称,大类编码,大类名,小类编码,小类名,进价,售价
FROM 销售表a LEFT JOIN 商品表b ON a.商品编码 = b.商品编码

如果您想把列的顺序排好:
SELECT 日期,店号,a.商品编码,商品名称,大类编码,大类名,小类编码,小类名,进价,售价,销售数量
FROM 销售表a LEFT JOIN 商品表b ON a.商品编码 = b.商品编码

如果您想计算销售金额
SELECT 日期,店号,a.商品编码,商品名称,大类编码,大类名,小类编码,小类名,进价,售价,销售数量,销售数量*售价 AS 销售金额
FROM 销售表a LEFT JOIN 商品表b ON a.商品编码 = b.商品编码

根据以上基础,我想设置日期为 2020-01-01 至 2020-01-03
SELECT 日期,店号,a.商品编码,商品名称,大类编码,大类名,小类编码,小类名,进价,售价,销售数量,销售数量售价 AS 销售金额
FROM 销售表a LEFT JOIN 商品表b ON a.商品编码 = b.商品编码
*WHERE 日期 BETWEEN ‘2020-01-01’ AND ‘2020-01-03’

【重要】根据以上基础,我想看每家店铺这一时间段内的 销售金额

SELECT 日期,店号,a.商品编码,商品名称,大类编码,大类名,小类编码,小类名,进价,售价,销售数量,销售数量售价 AS 销售金额,(销售数量售价)-(销售数量进 价) AS 毛利额
FROM 销售表a LEFT JOIN 商品表b ON a.商品编码 = b.商品编码
WHERE 日期 BETWEEN ‘2020-01-01’ AND ‘2020-01-03’
GROUP BY 店号
*ORDER BY 销售金额 DESC;

6.1.5 右外连接 RIGHT JOIN + ON

右连接:恰与左连接相反,返回右表中的所有行,如果右表中行在左表中没有匹配行,则结果中左表中的列返回空值。

image.png6.1.6 MySQL中实现 全外连接

概念:返回左表和右表中的所有行。当某行在另一表中没有匹配行,则另一表中的列返回空值。

image.png6.1.7 交叉连接 CROSS JOIN 笛卡尔积

没有Where子句,它返回连接表中所有数据行的笛卡尔积!
交叉连接:返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积

SELECT 徒弟,师傅 FROM 表a cross JOIN 表b

cross join 可以省略:
SELECT 徒弟,师傅 FROM 表a,表b

加上Where就变成内连接了
SELECT 徒弟,师傅 FROM 表a cross JOIN 表b WHERE 表a.师傅编号=表b.序号
SELECT 徒弟,师傅 FROM 表a,表b WHERE 表a.师傅编号=表b.序号

6.1.8 【重要】小结及多表连接的操作方法

内连接:inner join 如果表中至少有一个匹配,就返回行

左连接:会从左表中返回所有的值,即使右表中没有匹配

右连接:会从右表中返回所有的值,即使左表中没有匹配

拿到一个需求时,先学会分析:
(1)我要查询哪些数据? Select 字段名1,字段名2,……

(2)从哪几个表中查? From 表 或 XXX join连接表 ON 连接条件
(3)假设存在多张表查询,慢慢来,先查询两张表,再慢慢增加

例1:把销售表中的店名V过来,把商品名称V过来,

要求表头是:
日期,店号,店名,商品编码,商品名称,销售数量,销售成本,销售金额,毛利额

第一步:先把销售表和店铺表做连接,把店名先V来过
SELECT 日期,a.店号,店名,销售数量
FROM 销售表 a
LEFT JOIN 店铺表 b

ON a.店号=b.店号

第二步:再连接商品表,可以使用商品表中的商品名称、进价、售价
SELECT 日期,a.店号,店名,a.商品编码,商品名称,销售数量,销售数量进价 AS 销售成本,销售数量售价 AS 销售金额,销售数量(售价-进价) AS 毛利额
FROM 销售表 a
LEFT JOIN 店铺表 b
ON a.店号=b.店号
LEFT JOIN 商品表 c
*ON
a.商品编码=c.商品编码

例2:在例1的基础上,我想筛选时间为2020.01.01至2020.01.03

SELECT 日期,a.店号,店名,a.商品编码,商品名称,销售数量,销售数量进价 AS 销售成本,销售数量售价 AS 销售金额,销售数量(售价-进价) AS 毛利额
FROM 销售表 a
LEFT JOIN 店铺表 b
ON a.店号=b.店号
LEFT JOIN 商品表 c
ON a.商品编码=c.商品编码
WHERE 日期 BETWEEN ‘2020-01-01’ *AND
‘2020-01-03’

例3:在例2的基础上,假设我有100多家店铺,我只想看其中3家店铺的数据,查询1,3,7三家店铺的数据

SELECT 日期,a.店号,店名,a.商品编码,商品名称,销售数量,销售数量进价 AS 销售成本,销售数量售价 AS 销售金额,销售数量(售价-进价) AS 毛利额
FROM 销售表 a
LEFT JOIN 店铺表 b
ON a.店号=b.店号
LEFT JOIN 商品表 c
ON a.商品编码=c.商品编码
WHERE *a.店号 IN (1,3,7) AND
日期 BETWEEN ‘2020-01-01’ AND ‘2020-01-03’

例4:我现在不想要零散的日数据,我想要这三天,每家店铺的 总销售数量,总销售金额,总毛利额

SELECT a.店号,店名,sum(销售数量) AS 总销售,sum(销售数量进价) AS 总成本,sum(销售数量售价) AS 总金额,sum(销售数量*(售价-进价)) AS 毛利额
FROM 销售表 a
LEFT JOIN 店铺表 b
ON a.店号=b.店号
LEFT JOIN 商品表 c
ON a.商品编码=c.商品编码
WHERE a.店号 IN (1,3,7) AND 日期 BETWEEN ‘2020-01-01’ AND ‘2020-01-03’
GROUP BY a.店号

七, 子查询和嵌套查询

注意:一般在子查询中,程序先运行在嵌套在最内层的语句,再运行外层。因此在写子查询语句时,可以先测试下内层的子查询语句是否输出了想要的内容, 再一层层往外测试,增加子查询正确率。否则多层的嵌套使语句可读性很低。

子查询的特点
(1)子查询需要包含在小括号内。
(2)子查询通常放在筛选条件的右侧;这不是必需的,但系是约定成俗的。
(3)子查询不止用在查询中,增删改都能用,但是用在查询中较多,另外,99%的人都只能接触到查询工作。
(4)单行子查询,一般搭配配条件运算符使用,>、<、>=、<=、=、<>
(5)多行子查询,一般搭配着多行操作符使用,in、any/some、all
(6)子查询执行优先于主查询,主查询的条件用到了子查询的结果

子查询分类:
1、按子查询出现的位置:
Select后面:仅支持单行子查询
from后面:支持表子查询
where或having后面:单行子查询、多行子查询、多列多行子查询
exists相关子查询:表子查询

7.1 【重要】单行子查询 (子查询结果是一个值)

例1:查询平均销售量大于3号店的店铺
分析:
(1)我们要先查出3号店销售销售量的平均值
SELECT AVG(销售数量) AS 平均销量 FROM 销售表 WHERE 店号 in(3)

image.png

(2)查询大于3号店平均销售量的店铺
SELECT 店号,AVG(销售数量) AS 平均销量
FROM 销售表
GROUP BY 店号
HAVING AVG(销售数量)>(复制上一段代码);

image.png

例2:查询低于平均销量的店铺
分析:
(1)查询全部店铺平均销量
SELECT AVG(销售数量) AS 平均销量 FROM 销售表

image.png

(2)低于平均销量的店铺
SELECT 店号,AVG(销售数量) AS 平均销量
FROM 销售表
GROUP BY 店号
HAVING AVG(销售数量)<(复制上一段代码);

image.png

例3:查询大于2号店的平均销量,又小于7号店的平均销量,的店铺平均销量

分析:
(1)2店平均销售量
SELECT AVG(销售数量) AS 平均销量 FROM 销售表 WHERE 店号 in(2)

(2)7店平均销售量
SELECT AVG(销售数量) AS 平均销量 FROM 销售表 WHERE 店号 in(7)

(3)大于2店又小于7店平均销售量的店铺
SELECT 店号,AVG(销售数量) AS 平均销量
FROM 销售表

GROUP BY 店号
HAVING AVG(销售数量) > (复制2店代码) AND AVG(销售数量) < (复制7店代码)

image.png

也可以写成:
SELECT 店号,AVG(销售数量) AS 平均销量
FROM 销售表
GROUP BY 店号
HAVING AVG(销售数量) BETWEEN (复制2店代码) AND (复制7店代码);

人力、财务,例如你们查询,谁的工资比XXX人高
什么情况下放在Where后面呀?凡是表里有的字段放到Where后面。

总结:
凡是表里没有这个字段的时候(你自造的字段)必需用HAVING,不能使用WHERE
凡是字段名在FROM表中是唯一的,字段名前可以省略表名
凡是单行子查询,子查询必须是一个值,也就是说,子语句Select后面只能有一个字段名

7.2 【重要】多行子查询(子查询结果是多行)

image.png

7.2.1 【重要】in/not in

第一节课 我们在模糊查询里讲到的
where 店号 in(1,3,7)
where 大类编码 in(01,02,03)

而现在,多行子查询就是:in(子查询语句)
把里面的常量数值替换成了子查询语句

in 等于任意一个
not in 这里所有的都不是

7.2.2 ANY/SOME 可以用MIN/MAX代替

SOME是ANY一个别名,它们两个的用法和功能完全一样。

where(Having) 条件 > any(10,20,30)
# 大于其中任何一个值就可以,那么,他与使用Min有什么区别 呢?
where(Having) 条件 > min(10,20,30) # 用min替换了

======================================================= =========
where(Having) 条件 < any(10,20,30)
# 小于其中任何一个值就可以,那么,他与使用Max有什么区别 呢?
where(Having) 条件 < max(10,20,30) # 使用max替换 了

7.2.3 ALL所有的

where(Having) 条件 > all(10,20,30)

大于所有的,就是大于最大的
where(Having) 条件 < all(10,20,30)
小于所有的,就是小于最小的
也可以使用min和max代替

那么ANY和ALL的区别是什么呢?
(1)ANY :咱们打架,你们3个人,我1个人,游戏规则是,你们的人和我单挑,我打赢了任何一个人都算我赢,假设你们第1个人把我打败了,第2个人再跟 我打,如果我还是败,第3个人再跟我打。假设第1个人就被我打败了,后面两个不打了,我赢了。

(2)ALL:咱们打架,你们3个人,我1个人,游戏规则是,你们的人和我单挑,但是我要把你们的每一个人都打赢了才算我赢了。

7.2.4 一行多列或多行多列子查询 【新人不推荐】

image.png

7.2.5 Select 后面子查询

例如:查询每个店铺经营的品种数(当然条件上你肯定要锁定一个时间段我就不加了)

select a.店号,a.店名,(
select count(*)

from 商品表 b
where b.商品编码 = a.商品编码 )
AS 品种数
From 销售表 a;

这只是举例,不一定要用这种方式,以前的方法同样可以做出来

切记:只能放一行一列的子查询

7.2.6 From 后面子查询

image.png

7.2.7 相关子查询

EXISTS (子查询) # 就是判断
返回结果是:1或0

两者明显不同的是,EXISTS常用于判断查询集是否为空,只要子查询中至 少返回一个值,EXISTS判断结果即为TRUE;子查询的结果表中没有值, EXISTS返回FALSE。

例如:查询有员工的部门名

select 部门名
from 部门表 a where exists (
select * from 员工表 b
where a.部门编号 = b.部门编号 );

EXISTS:先执行主查询某个字段的值,根据子查询进行过滤 因为子查询涉及到了主查询的字段,所以叫相关子查询。

举个大家都能看得懂的例子:
image.png
image.png






















  1. <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br />