├── README.md ├── SQL基础教程.pdf ├── Task00:绪论 - 环境搭建.md ├── Task01:初识数据库.md ├── Task02:基础查询与排序.md ├── Task03:复杂一点的查询.md ├── Task04:集合运算.md ├── Task05:SQL高级处理.md ├── Task06:综合练习.md ├── img ├── .gitkeep ├── 00 SQL基础课程.png ├── ch00 │ ├── .gitkeep │ ├── ch0001.png │ ├── ch0002.png │ ├── ch0003.png │ ├── ch0004.png │ ├── ch0005.png │ ├── ch0006.png │ ├── ch0007.png │ ├── ch0008.png │ ├── ch0009.png │ ├── ch0010.png │ ├── ch0011.png │ ├── ch0012.png │ ├── ch0013.png │ ├── ch0014.png │ ├── ch0015.png │ ├── ch0016.png │ ├── ch0017.png │ ├── ch0018.png │ ├── ch0019.png │ ├── ch0020.png │ ├── ch0021.png │ ├── ch0022.png │ ├── ch0023.png │ ├── ch0024.png │ ├── ch0025.png │ ├── ch0026.png │ ├── ch0027.png │ ├── ch0028.png │ ├── ch0029.png │ ├── ch0030.png │ ├── ch0031.png │ ├── ch0032.png │ ├── ch0033.png │ ├── ch0034.png │ ├── ch0035.png │ ├── ch0036.png │ ├── ch0037.png │ ├── ch0038.png │ ├── ch0039.png │ ├── ch0040.png │ ├── ch0041.png │ ├── ch0042.png │ ├── ch0043.png │ ├── ch0044.png │ ├── ch0045.png │ ├── ch0046.png │ ├── ch0047.png │ ├── ch0048.png │ ├── ch0049.png │ ├── ch0050.png │ ├── ch0051.png │ ├── ch0052.png │ ├── ch0053.png │ ├── ch0054.png │ ├── ch00541.png │ ├── ch0055.png │ ├── ch0056.png │ ├── ch0057.png │ ├── ch0058.png │ ├── ch0059.png │ ├── ch0060.png │ ├── ch0061.png │ ├── ch0062.png │ ├── ch0063.png │ ├── ch0064.png │ ├── ch0065.png │ ├── ch0066.png │ ├── ch0067.png │ ├── ch0068.png │ ├── ch0069.png │ ├── ch0070.png │ ├── ch0071.png │ ├── ch0072.png │ ├── ch0073.png │ ├── ch0074.png │ └── ch0075.png ├── ch01 │ ├── .gitkeep │ ├── ch01.01系统结构.jpg │ ├── ch01.02表的示例.jpg │ ├── ch01.03商品表和列名对应关系.png │ └── ch01.04习题1.png ├── ch02 │ ├── .gitkeep │ ├── ch02.01and.png │ ├── ch02.02or.png │ ├── ch02.03true.png │ ├── ch02.04true2.png │ ├── ch02.05true3.png │ ├── ch02.06cut.png │ ├── ch02.07groupby.png │ ├── ch02.08test26.png │ └── ch02.09test27.png ├── ch03 │ ├── .gitkeep │ ├── ch03.01view.png │ ├── ch03.02view2.png │ ├── ch03.03view3.png │ ├── ch03.04view4.png │ ├── ch03.05result.png │ ├── ch03.06productsum.png │ ├── ch03.07productsum2.png │ ├── ch03.08productsumsrc.png │ ├── ch03.09case.png │ ├── ch03.10function.png │ ├── ch03.11casewhen1.png │ └── ch03.12casewhen2.png ├── ch04 │ ├── .gitkeep │ ├── ch04.01.png │ ├── ch04.02.png │ ├── ch04.03union.png │ ├── ch04.04result.png │ ├── ch04.05result2.png │ ├── ch04.06result3.png │ ├── ch04.07result4.png │ ├── ch04.08result5.png │ ├── ch04.09except.png │ ├── ch04.10.png │ ├── ch04.11.png │ ├── ch04.12.png │ ├── ch04.13join.png │ ├── ch04.14tb.png │ ├── ch04.15shopproduct.png │ ├── ch04.16tb73.png │ ├── ch04.17result.png │ ├── ch04.18result2.png │ ├── ch04.19result3.png │ ├── ch04.20.png │ ├── ch04.21.png │ ├── ch04.22.png │ ├── ch04.23.png │ ├── ch04.24.png │ ├── ch04.25.png │ ├── ch04.26.png │ ├── ch04.27.png │ ├── ch04.28.png │ ├── ch04.29.png │ ├── ch04.30.png │ ├── ch04.31.png │ ├── ch04.32.png │ ├── ch04.33.png │ ├── ch04.34.png │ ├── ch04.35.png │ ├── ch04.36.png │ └── ch04.37.png ├── ch05 │ ├── .gitkeep │ ├── ch0501.png │ ├── ch0502.png │ ├── ch0503.png │ ├── ch0504.png │ ├── ch0505.png │ ├── ch0506.png │ ├── ch0507.png │ ├── ch0508.png │ ├── ch0509.png │ └── ch0510.png └── datawhale_code.jpeg └── shop.sql /README.md: -------------------------------------------------------------------------------- 1 | # SQL基础教程学习笔记(team-learning-sql) 2 | 3 | # 最新项目地址为 [https://github.com/datawhalechina/wonderful-sql](https://github.com/datawhalechina/wonderful-sql) 4 | 5 | SQL 在诸多工作中应用广泛,数据分析、开发、测试、维护、产品经理都有可能会用到SQL,而在大学里曾经系统学习SQL的人比较少, 6 | 这就要求我们在工作中来学习SQL。然而,自己学习很容易走弯路。笔者通过近几年的摸索学习,发现了一本很好的教材[《SQL基础教程 第2版》](https://book.douban.com/subject/27055712/)作者:MICK, 7 | 我如获至宝,心想这么好的教材应该让更多的人了解到,以便小伙伴们少走弯路,于是乎,我就联合DataWhale团队成员编写了这一版学习笔记。希望可以帮你更好的学习SQL。 8 | 9 | ## 使用方法 10 | 11 | 考虑到易用性和普及度,课程内容采用`MySql`进行介绍,对教材内容进行了整合,具体的目录参见下方,每个章节附带了练习题,最后一个章节是 12 | leetcode练习题和大厂面试题,顺利完成本课程学习后,应付初级SQL面试不在话下,还等什么呢?现在就开始吧~~ 13 | 14 | ## 目录 15 | 16 | * Task00:绪论 - 环境搭建 17 | - [x] [1. MySQL 8.0 的安装](https://github.com/datawhalechina/team-learning-sql/blob/main/Task00%EF%BC%9A%E7%BB%AA%E8%AE%BA%20-%20%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#1-mysql-80-%E7%9A%84%E5%AE%89%E8%A3%85) 18 | - [x] [2. 连接 MySQL 并执行 SQL 查询](https://github.com/datawhalechina/team-learning-sql/blob/main/Task00%EF%BC%9A%E7%BB%AA%E8%AE%BA%20-%20%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#2-%E8%BF%9E%E6%8E%A5-mysql-%E5%B9%B6%E6%89%A7%E8%A1%8C-sql-%E6%9F%A5%E8%AF%A2) 19 | 20 | * Task01:初识数据库 21 | - [x] [1.1 初识数据库](https://github.com/datawhalechina/team-learning-sql/blob/main/Task01%EF%BC%9A%E5%88%9D%E8%AF%86%E6%95%B0%E6%8D%AE%E5%BA%93.md#11-%E5%88%9D%E8%AF%86%E6%95%B0%E6%8D%AE%E5%BA%93) 22 | - [x] [1.2 初识SQL](https://github.com/datawhalechina/team-learning-sql/blob/main/Task01%EF%BC%9A%E5%88%9D%E8%AF%86%E6%95%B0%E6%8D%AE%E5%BA%93.md#11-%E5%88%9D%E8%AF%86%E6%95%B0%E6%8D%AE%E5%BA%93) 23 | 24 | * Task02:基础查询与排序 25 | - [x] [2.1 SELECT语句基础](https://github.com/datawhalechina/team-learning-sql/blob/main/Task02%EF%BC%9A%E5%9F%BA%E7%A1%80%E6%9F%A5%E8%AF%A2%E4%B8%8E%E6%8E%92%E5%BA%8F.md#21-select%E8%AF%AD%E5%8F%A5%E5%9F%BA%E7%A1%80) 26 | - [x] [2.2 算术运算符和比较运算符](https://github.com/datawhalechina/team-learning-sql/blob/main/Task02%EF%BC%9A%E5%9F%BA%E7%A1%80%E6%9F%A5%E8%AF%A2%E4%B8%8E%E6%8E%92%E5%BA%8F.md#22-%E7%AE%97%E6%9C%AF%E8%BF%90%E7%AE%97%E7%AC%A6%E5%92%8C%E6%AF%94%E8%BE%83%E8%BF%90%E7%AE%97%E7%AC%A6) 27 | - [x] [2.3 逻辑运算符](https://github.com/datawhalechina/team-learning-sql/blob/main/Task02%EF%BC%9A%E5%9F%BA%E7%A1%80%E6%9F%A5%E8%AF%A2%E4%B8%8E%E6%8E%92%E5%BA%8F.md#23-%E9%80%BB%E8%BE%91%E8%BF%90%E7%AE%97%E7%AC%A6) 28 | - [x] [2.4 对表进行聚合查询](https://github.com/datawhalechina/team-learning-sql/blob/main/Task02%EF%BC%9A%E5%9F%BA%E7%A1%80%E6%9F%A5%E8%AF%A2%E4%B8%8E%E6%8E%92%E5%BA%8F.md#24-%E5%AF%B9%E8%A1%A8%E8%BF%9B%E8%A1%8C%E8%81%9A%E5%90%88%E6%9F%A5%E8%AF%A2) 29 | - [x] [2.5 对表进行分组](https://github.com/datawhalechina/team-learning-sql/blob/main/Task02%EF%BC%9A%E5%9F%BA%E7%A1%80%E6%9F%A5%E8%AF%A2%E4%B8%8E%E6%8E%92%E5%BA%8F.md#25-%E5%AF%B9%E8%A1%A8%E8%BF%9B%E8%A1%8C%E5%88%86%E7%BB%84) 30 | - [x] [2.6 为聚合结果指定条件](https://github.com/datawhalechina/team-learning-sql/blob/main/Task02%EF%BC%9A%E5%9F%BA%E7%A1%80%E6%9F%A5%E8%AF%A2%E4%B8%8E%E6%8E%92%E5%BA%8F.md#26-%E4%B8%BA%E8%81%9A%E5%90%88%E7%BB%93%E6%9E%9C%E6%8C%87%E5%AE%9A%E6%9D%A1%E4%BB%B6) 31 | 32 | * Task03:复杂一点的查询 33 | - [x] [3.1 视图](https://github.com/datawhalechina/team-learning-sql/blob/main/Task03%EF%BC%9A%E5%A4%8D%E6%9D%82%E4%B8%80%E7%82%B9%E7%9A%84%E6%9F%A5%E8%AF%A2.md#31-%E8%A7%86%E5%9B%BE) 34 | - [x] [3.2 子查询](https://github.com/datawhalechina/team-learning-sql/blob/main/Task03%EF%BC%9A%E5%A4%8D%E6%9D%82%E4%B8%80%E7%82%B9%E7%9A%84%E6%9F%A5%E8%AF%A2.md#33-%E5%90%84%E7%A7%8D%E5%90%84%E6%A0%B7%E7%9A%84%E5%87%BD%E6%95%B0) 35 | - [x] [3.3 各种各样的函数](https://github.com/datawhalechina/team-learning-sql/blob/main/Task03%EF%BC%9A%E5%A4%8D%E6%9D%82%E4%B8%80%E7%82%B9%E7%9A%84%E6%9F%A5%E8%AF%A2.md#33-%E5%90%84%E7%A7%8D%E5%90%84%E6%A0%B7%E7%9A%84%E5%87%BD%E6%95%B0) 36 | - [x] [3.4 谓词](https://github.com/datawhalechina/team-learning-sql/blob/main/Task03%EF%BC%9A%E5%A4%8D%E6%9D%82%E4%B8%80%E7%82%B9%E7%9A%84%E6%9F%A5%E8%AF%A2.md#34-%E8%B0%93%E8%AF%8D) 37 | - [x] [3.5 CASE 表达式](https://github.com/datawhalechina/team-learning-sql/blob/main/Task03%EF%BC%9A%E5%A4%8D%E6%9D%82%E4%B8%80%E7%82%B9%E7%9A%84%E6%9F%A5%E8%AF%A2.md#35-case-%E8%A1%A8%E8%BE%BE%E5%BC%8F) 38 | 39 | * Task04:集合运算 40 | - [x] [4.1 表的加减法](https://github.com/datawhalechina/team-learning-sql/blob/main/Task04%EF%BC%9A%E9%9B%86%E5%90%88%E8%BF%90%E7%AE%97.md#41-%E8%A1%A8%E7%9A%84%E5%8A%A0%E5%87%8F%E6%B3%95) 41 | - [x] [4.2 连结(JOIN)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task04%EF%BC%9A%E9%9B%86%E5%90%88%E8%BF%90%E7%AE%97.md#42-%E8%BF%9E%E7%BB%93join) 42 | 43 | * Task05:SQL高级处理 44 | - [x] [5.1 窗口函数](https://github.com/datawhalechina/team-learning-sql/blob/main/Task05%EF%BC%9ASQL%E9%AB%98%E7%BA%A7%E5%A4%84%E7%90%86.md#51-%E7%AA%97%E5%8F%A3%E5%87%BD%E6%95%B0) 45 | - [x] [5.2 窗口函数种类](https://github.com/datawhalechina/team-learning-sql/blob/main/Task05%EF%BC%9ASQL%E9%AB%98%E7%BA%A7%E5%A4%84%E7%90%86.md#52-%E7%AA%97%E5%8F%A3%E5%87%BD%E6%95%B0%E7%A7%8D%E7%B1%BB) 46 | - [x] [5.3 窗口函数的的应用 - 计算移动平均](https://github.com/datawhalechina/team-learning-sql/blob/main/Task05%EF%BC%9ASQL%E9%AB%98%E7%BA%A7%E5%A4%84%E7%90%86.md#53-%E7%AA%97%E5%8F%A3%E5%87%BD%E6%95%B0%E7%9A%84%E7%9A%84%E5%BA%94%E7%94%A8---%E8%AE%A1%E7%AE%97%E7%A7%BB%E5%8A%A8%E5%B9%B3%E5%9D%87) 47 | - [x] [5.4 GROUPING运算符](https://github.com/datawhalechina/team-learning-sql/blob/main/Task05%EF%BC%9ASQL%E9%AB%98%E7%BA%A7%E5%A4%84%E7%90%86.md#54-grouping%E8%BF%90%E7%AE%97%E7%AC%A6) 48 | 49 | * Task06:综合练习 50 | - [x] [6.1 练习一: 各部门工资最高的员工(难度:中等)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E4%B8%80-%E5%90%84%E9%83%A8%E9%97%A8%E5%B7%A5%E8%B5%84%E6%9C%80%E9%AB%98%E7%9A%84%E5%91%98%E5%B7%A5%E9%9A%BE%E5%BA%A6%E4%B8%AD%E7%AD%89) 51 | - [x] [6.2 练习二: 换座位(难度:中等)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E4%BA%8C-%E6%8D%A2%E5%BA%A7%E4%BD%8D%E9%9A%BE%E5%BA%A6%E4%B8%AD%E7%AD%89) 52 | - [x] [6.3 练习三: 分数排名(难度:中等)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E4%B8%89--%E5%88%86%E6%95%B0%E6%8E%92%E5%90%8D%E9%9A%BE%E5%BA%A6%E4%B8%AD%E7%AD%89) 53 | - [x] [6.4 练习四:连续出现的数字(难度:中等)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E5%9B%9B%E8%BF%9E%E7%BB%AD%E5%87%BA%E7%8E%B0%E7%9A%84%E6%95%B0%E5%AD%97%E9%9A%BE%E5%BA%A6%E4%B8%AD%E7%AD%89) 54 | - [x] [6.5 练习五:树节点 (难度:中等)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E4%BA%94%E6%A0%91%E8%8A%82%E7%82%B9-%E9%9A%BE%E5%BA%A6%E4%B8%AD%E7%AD%89) 55 | - [x] [6.6 练习六:至少有五名直接下属的经理 (难度:中等)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E5%85%AD%E8%87%B3%E5%B0%91%E6%9C%89%E4%BA%94%E5%90%8D%E7%9B%B4%E6%8E%A5%E4%B8%8B%E5%B1%9E%E7%9A%84%E7%BB%8F%E7%90%86-%E9%9A%BE%E5%BA%A6%E4%B8%AD%E7%AD%89) 56 | - [x] [6.7 练习七: 分数排名 (难度:中等)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E4%B8%83-%E5%88%86%E6%95%B0%E6%8E%92%E5%90%8D--%E9%9A%BE%E5%BA%A6%E4%B8%AD%E7%AD%89) 57 | - [x] [6.8 练习八:查询回答率最高的问题 (难度:中等)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E5%85%AB%E6%9F%A5%E8%AF%A2%E5%9B%9E%E7%AD%94%E7%8E%87%E6%9C%80%E9%AB%98%E7%9A%84%E9%97%AE%E9%A2%98-%E9%9A%BE%E5%BA%A6%E4%B8%AD%E7%AD%89) 58 | - [x] [6.9 练习九:各部门前3高工资的员工(难度:中等)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E4%B9%9D%E5%90%84%E9%83%A8%E9%97%A8%E5%89%8D3%E9%AB%98%E5%B7%A5%E8%B5%84%E7%9A%84%E5%91%98%E5%B7%A5%E9%9A%BE%E5%BA%A6%E4%B8%AD%E7%AD%89) 59 | - [x] [6.10 练习十:平面上最近距离 (难度: 困难)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E5%8D%81%E5%B9%B3%E9%9D%A2%E4%B8%8A%E6%9C%80%E8%BF%91%E8%B7%9D%E7%A6%BB-%E9%9A%BE%E5%BA%A6-%E5%9B%B0%E9%9A%BE) 60 | - [x] [6.11 练习十一:行程和用户(难度:困难)](https://github.com/datawhalechina/team-learning-sql/blob/main/Task06%EF%BC%9A%E7%BB%BC%E5%90%88%E7%BB%83%E4%B9%A0.md#%E7%BB%83%E4%B9%A0%E5%8D%81%E4%B8%80%E8%A1%8C%E7%A8%8B%E5%92%8C%E7%94%A8%E6%88%B7%E9%9A%BE%E5%BA%A6%E5%9B%B0%E9%9A%BE) 61 | 62 | 63 | 64 | ## 常见问题 65 | 66 | - **在线教程页面无法打开**: 67 | 68 | 测试中存在部分人打不开在线教程的情况。 69 | 70 | 部分小伙伴反馈尝试切换浏览器后可以正常打开了,如果仍然不行,最有效的解决办法是科学上网。 71 | 72 | - **无法加载图片的解决办法**: 73 | 74 | 根本解决办法还是科学上网,也可以尝试修改host文件看下是否能解决。 75 | 76 | [windows解决方案:修改host文件](https://blog.csdn.net/u011583927/article/details/104384169) 77 | 78 | 79 | ## 致谢 80 | 81 | 感谢以下Datawhale成员对项目推进作出的贡献(排名不分先后): 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |
贡献者名单
成员个人简介及贡献个人主页
王复振Datawhale成员,项目负责人,Task00/01/03内容构建 CSDN博客
杨煜数据分析师,公众号:BI数据可视化,Datawhale成员,Task05/06内容构建
闫钟峰图书馆员,Datawhale成员,Task00/04内容构建
杨梦迪上海大学硕士,Datawhale成员,Task02内容构建
苏鹏东北大学硕士,Datawhale成员,Task00/01/03内容构建Github
红星广东工业大学,Datawhale成员,内测小组成员
张晋北京理工大学,Datawhale成员,内测小组成员
汪健麟电子科技大学硕士,Datawhale成员,内测小组成员
苏丽敏北京理工大学硕士,Datawhale成员,助教
140 | 141 | 142 | ## 关注我们 143 | 144 | > "Datawhale是一个专注AI领域的开源组织,以“for the learner,和学习者一起成长”为愿景,构建对学习者最有价值的开源学习社区。关注我们,一起学习成长。" 145 | 146 | 147 | -------------------------------------------------------------------------------- /SQL基础教程.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/SQL基础教程.pdf -------------------------------------------------------------------------------- /Task00:绪论 - 环境搭建.md: -------------------------------------------------------------------------------- 1 | # 本章重点: 2 | * 在电脑上安装MySQL数据库系统 3 | * 安装客户端并连接到本机上的MySQL数据库 4 | * 使用提供的脚本创建本教程所使用的示例数据库 5 | # 1. MySQL 8.0 的安装 6 | 7 | 考虑到大家所使用的操作系统的不同, 本教程分别提供了 windows 10, macOS和centos平台上的MySQL 8.0 的安装流程, 你可根据自己所使用电脑的操作系统选择以下三节中的一节进行学习和安装. 8 | 9 | ## 1.1 windows 下 MySQL 8.0 的下载安装 10 | 11 | 首先以最常见的 win10 为例, 介绍 MySQL8.0 的下载安装. 12 | 13 | ### 1.1.1 下载 14 | 15 | MySQL 针对个人用户和商业用户提供了不同的版本, MySQL 社区版(MySQL Community Edition) 是供个人用户免费下载的开源数据库, 本教程将以MySQL 社区版为例进行安装连接和SQL查询的讲解. 16 | 17 | MySQL 官网上的社区版软件的下载地址[https://dev.mysql.com/downloads/](https://dev.mysql.com/downloads/), 选择[MySQL Installer for Windows](https://dev.mysql.com/downloads/windows/)可以下载 windows 操作系统下的最新版 MySQL安装文件. 如果需要安装历史版本, 可以选择最后的[Download Archives](https://downloads.mysql.com/archives/)后选择[MySQL Installer](https://downloads.mysql.com/archives/installer/),然后在新页面里选择所需历史版本的社区版. 18 | 19 | 如果想下载本教程所使用的 MySQL 8.0.21.0, 也可以在百度⽹盘下载, 20 | 21 | 下载链接:[https://pan.baidu.com/s/1SOtMoVqqRXwa2qD0siHcIg](https://pan.baidu.com/s/1SOtMoVqqRXwa2qD0siHcIg)提取码:80lf 22 | 23 | 备用下载链接:[https://pan.baidu.com/s/1zK2vj50DvuAee-EqAcl-0A](https://pan.baidu.com/s/1zK2vj50DvuAee-EqAcl-0A)提取码:80lf 24 | 25 | 我们接下来以文档写作时的最新版 MySQL 8.0.21 为例, 进行下载安装的介绍. 26 | 27 | 进入到[MySQL Installer for Windows](https://dev.mysql.com/downloads/windows/)页面后, 选择下载下方的完整安装程序. 28 | 29 | ![图片](./img/ch00/ch0001.png) 30 | 31 | 在下载页面选择下方的不注册,仅下载. 32 | 33 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0002.png) 34 | 35 | 完成下载后, 得到一个后缀为msi的安装文件. 36 | 37 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0003.png) 38 | 39 | ### 1.1.2 安装 40 | 41 | 找到刚才下载好的msi文件, 双击开始安装. 初学者建议采用完全安装模式(Full)进行安装: 42 | 43 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0004.png) 44 | 45 | 选择安装路径和数据存放路径, 二者都可以选择在非系统盘(注意要点击最右侧的按钮进行选择, 不要直接在文本框中修改安装路径). 46 | 47 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0005.png) 48 | 49 | 完全安装模式下, 部分模块会依赖其他其他组件(每台电脑上列出的依赖项很可能会有不同). 50 | 51 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0006.png) 52 | 53 | 如果你的电脑之前没有安装过这些组件, 则需要额外进行安装, 此处点击 Execute 按钮即可: 54 | 55 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0007.png) 56 | 57 | 在这些所依赖的组件的安装过程中, 只需要一路选择"同意"并逐个安装就可以了: 58 | 59 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0008.png) 60 | 61 | 安装好⼀个组件后, 点击关闭按钮, ⾃动开始安装下⼀个组件(这一步根据操作系统版本可能会略有不同) 62 | 63 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0009.png) 64 | 65 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0010.png) 66 | 67 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0011.png) 68 | 69 | 正常情况下,会将所有组件安装成功.但可能会有个别组件未安装成功. 个别组件没有呈现绿⾊是因为你的电脑中缺少某个程序, 例如, 如果你的电脑没有安装 Python 环境, 则该项目就不会呈现绿色. 待下边剩下 3 个按钮且上⽅⼤部分组件为绿色时, 即可点击 Next: 70 | 71 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0012.png) 72 | 73 | 如果有个别组件未安装成功, 此时可以先选择 Yes, 忽略个别组件的安装. 74 | 75 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0013.png) 76 | 77 | 点击 Excute, 开始安装服务器软件MySQL Server, 连接和查询软件MySQL Workbench及其他相关软件等内容. 78 | 79 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0014.png) 80 | 81 | 稍等片刻, 安装完成后, 点击 Next 82 | 83 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0015.png) 84 | 85 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0016.png) 86 | 87 | 下图这一步是选是否以集群方式安装 MySQL, 我们选择默认的第一个, 然后点击 Next: 88 | 89 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0017.png) 90 | 91 | 此处上边的各种相关配置保持默认即可,**勾选最下边的"Show Advanced and Logging Options"框,**然后点击 Next: 92 | 93 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0018.png) 94 | 95 | 下图是密码强度的设置, 第⼀种模式为强密码校验模式, MySQL 8.0 推荐使⽤最新的数据库和客户端, 更换了加密插件, 者可能导致第三⽅客户端⼯具⽆法连接数据库. 96 | 97 | 第⼆种加密⽅式沿袭了 MySQL 5.x 的加密⽅式, 对第三⽅⼯具连接不敏感, 我们仅为了学习 SQL 查询, 并不需要很高的安全性, 因此此处请务必选择第二种⽅式(非常重要): 98 | 99 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0019.png) 100 | 101 | 在这一步设置 MySQL 的 root 账户密码, 由于上一步选择了第二个选项, 因此这里可以设置为较简单容易记忆的而密码, 例如"123456". 建议设置⽐较简单的密码, 并将密码记录下来以防遗忘, 忘记密码是⼀件麻烦事. 102 | 103 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0020.png) 104 | 105 | 此处保持默认即可, 如果 windows service name 右侧有⻩⾊警告图标显示, 表示名称重复, ⼿动更换⼀个名称即可, 然后点击 Next: 106 | 107 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0021.png) 108 | 109 | Logging Options 这里使用默认设置即可, 我们的学习中暂时用不到这些设置, 直接点击 Next: 110 | 111 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0022.png) 112 | 113 | 下图是设置是否大小写敏感的. 这一步非常重要,**由于windows系统是大小写不敏感的, 请大家务必使用第一个选项Lower Case**. 114 | 115 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0023.png) 116 | 117 | 点击 Execute 118 | 119 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0024.png) 120 | 121 | 完成安装后, 在下图中点击 Finish 回到安装的主进程: 122 | 123 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0025.png) 124 | 125 | 在主进程界面点击 Next 126 | 127 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0026.png) 128 | 129 | 这一步无需任何选择, 直接点击 Finish 130 | 131 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0027.png) 132 | 133 | 进入到 Connect To Server 界面后, 输⼊刚才设置的密码, 点击 check 进⾏校验, 校验通过后 Status 会显示连接成功, 然后点击 Next 134 | 135 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0028.png) 136 | 137 | 点击 Excute 应用设置: 138 | 139 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0029.png) 140 | 141 | 上述步骤完成后, 点击 Finish 142 | 143 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0030.png) 144 | 145 | 回到安装主进程后, 点击 Next 146 | 147 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0031.png) 148 | 149 | 点击 Finish,完成安装. 150 | 151 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0032.png) 152 | 153 | 现在, 你的电脑上就已经安装了MySQL的服务器软件, 用于连接服务器进行查询的MySQL Workbench, 以及其他程序语言连接MySQL的驱动, 此外还安装了几个示例数据库, 但本教程将采用一书中的示例数据库, 该数据库的创建和数据导入将在本章第三节介绍. 154 | 155 | 156 | ## 1.2 macOS 下 MySQL 8.0 的下载安装 157 | 158 | MySQL 官网上社区版软件的下载地址[https://dev.mysql.com/downloads/](https://dev.mysql.com/downloads/), 选择[MySQL Community Server](https://dev.mysql.com/downloads/mysql/)可以进一步选择下载 macOS操作系统下的最新版 MySQL. 如果需要安装历史版本, 可以选择最后的[Download Archives](https://downloads.mysql.com/archives/)后选择[MySQL Installer](https://downloads.mysql.com/archives/installer/),然后在新页面里选择所需历史版本的社区版. 159 | 160 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0033.png) 161 | 162 | 然后选择下载dmg安装文件. 163 | 164 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0034.png) 165 | 166 | 点击下方的直接下载. 167 | 168 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0035.png) 169 | 170 | 下载的文件为: 171 | 172 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0036.png) 173 | 174 | 如果官网下载速度很慢, 或者希望下载本教程所使用的 MySQL 8.0.21.0, 也可以在百度⽹盘下载, 175 | 176 | 下载链接:[https://pan.baidu.com/s/1ka22UtzqFdOaIosrpKz92w](https://pan.baidu.com/s/1ka22UtzqFdOaIosrpKz92w)提取码: 8xh4 177 | 178 | 备用下载链接:[https://pan.baidu.com/s/1XeA_8PQvvRePEdZ5ayOT-Q](https://pan.baidu.com/s/1XeA_8PQvvRePEdZ5ayOT-Q)提取码:8xh4 179 | 180 | 181 | 我们接下来以文档写作时的最新版为 8.0.21 为例, 进行下载安装讲解. 182 | 183 | 在mac上直接双击dmg文件就可以开始安装了. 我们只选择了安装MySQL Community Server, 因此安装过程较为简单. 184 | 185 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0037.png) 186 | 187 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0038.png) 188 | 189 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0039.png) 190 | 191 | 注意, 在配置MySQL服务器这一步, 最好选择下边的选项, 这样就可以使用简单密码. 192 | 193 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0040.png) 194 | 195 | 在 Configuration 接下来的步骤需要设置密码, 如果上一步选择了第二个选项, 这里就可以使用比较简单的密码. 请务必牢记自己设置的密码. 196 | 197 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0041.png) 198 | 199 | 注意, 如果在前一步选择使用了MySQL8.0强密码, MySQL安装过程中会自动生成一个随机密码, 类似于下图这种形式: 200 | 201 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0042.png) 202 | 203 | 此时请截图保留该密码, 并在安装完成后, 使用该密码登录并重新设置密码. 由于选择使用了强密码, 此时设置密码必须使用大小写字母数字和特殊符号的组合. 204 | 205 | 完成安装后, 打开电脑的系统偏好设置, 会出现MySQL的服务标识. 206 | 207 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0043.png) 208 | 209 | 正确安装MySQL后, 打开上述截图中的MySQL之后会看到如下界面, 在这里可以启动和停止MySQL服务, 以及配置MySQL是否随电脑启动而自动启动. 210 | 211 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0044.png) 212 | 213 | 安装之后, 如果我们直接在终端输入mysql, 会提示找不到命令, 需要配置一下环境变量才可以, 输入以下命令: 214 | 215 | ```plain 216 | PATH="$PATH":/usr/local/mysql/bin 217 | ``` 218 | 再通过终端输入mysql登录命令后, 就可以看到mysql的交互式界面了. 219 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0045.png) 220 | 221 | 然后输入以下内容, 将自己电脑的mysql路径配置到环境变量中, 如果在安装过程中你没修改过安装路径, 那么你的电脑上MySQL的路径应该和下述代码中所使用的路径是一致的: 222 | 223 | ```plain 224 | export PATH=$PATH:/usr/local/mysql/bin 225 | ``` 226 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0046.png) 227 | 228 | 运行上述配置后, 通过输入下面这条命令使修改生效 229 | 230 | ```plain 231 | source ~/.bash_profile 232 | ``` 233 | 接下来, 在你的终端中输入命令来登录到MySQL 234 | ```plain 235 | mysql -u root -p 236 | ``` 237 | 然后需要输入你刚才设置的密码(如果你选择了强密码, 则这里需要输入你查到的随机密码), 如果看到以下界面, 则表示你的电脑上: 1.MySQL8.0已经正确安装, 2.已经正确配置了MySQL8.0的环境变量,并且3.已经启动MySQL服务器程序. 如果并没有出现下属界面, 请按照上述三个顺序逐个检查. 238 | 239 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0047.png) 240 | 241 | 使用终端(或者windows下的命令行)与MySQL进行交互是非常便捷和高效的, 但是对于平时不怎么使用终端的普通人来说, 使用终端在做数据查询时, 在查询结果的显示和导出方面有诸多不便, 特别是当我们对 SQL 查询不熟练的时候, 这种方式很不利于我们进行查询语句的调试. 因此本教程将选择查询界面更加友好的客户端工具来连接数据库, 这种通过终端连接MySQL的方式暂时不再使用. 242 | 243 | 接下来请安装跳转到2.1节安装MySQL Workbench并连接本机的MySQL服务. 244 | 245 | >注: 246 | >macOS上的SQL查询工具也有很多其他的选择, 比如DBeaver(开源, 免费), DataGrip(需付费购买,提供30天的免费试用期, 学生使用学校的邮箱可以申请到一年的免费使用权)等,可参考知乎上的问题 : 247 | >Mac平台上有哪些好的SQL 数据库开发工具?[https://www.zhihu.com/question/20498949](https://www.zhihu.com/question/20498949) 248 | ## 249 | 250 | 251 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0048.png) 252 | 253 | 254 | ## 1.3 Linux 下 MySQL 8.0 的下载安装 255 | 256 | 本节我们以 centos 版本的 Linux 操作系统为例, 介绍下载安装 MySQL8.0.21 的过程. 示例操作系统的linux 版本:centos-release-7-7.1908.0.el7.centos.x86_64 257 | 258 | 在 CentOS 系统中默认是安装了 MariaDB 的, 但是我们需要的是 MySQL, 我们可以直接下载安装 MySQL, 安装 MySQL 可以覆盖 MariaDB. 259 | 260 | >关于 MariaDB: 261 | >MariaDB 数据库管理系统是 MySQL 的一个分支, 主要由开源社区在维护, 采用 GPL 授权许可. 开发这个分支的原因之一是:甲骨文公司收购了 MySQL 后, 有将 MySQL 闭源的潜在风险, 因此社区采用分支的方式来避开这个风险. MariaDB 的目的是完全兼容 MySQL, 包括 API 和命令行, 使之能轻松成为 MySQL 的代替品. 但在两个分支经过了几年的各自迭代之后, 在一些方面二者出现了一些差异. 262 | ### 263 | ### 1.3.1 安装步骤: 264 | 265 | 首先, 从[MySQL官网](https://dev.mysql.com/downloads/repo/yum/)下载 MySQL 的 Yum Repository. 根据 CentOS 和 MySQL 的版本,选择下载相对应的文件. 本文选择红色方框的文件. 266 | 267 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0049.png) 268 | 269 | Yum 是一个基于 rpm 的软件包管理器, 它可以从指定的服务器自动下载 RPM 包并且安装, 可以自动处理依赖性关系, 并且一次安装所有依赖的软体包, 无须繁琐地一次次下载、安装. 270 | 271 | 下载命令: 272 | 273 | ```plain 274 | wget https://dev.mysql.com/get/mysql80-community-release-el7-2.noarch.rpm 275 | ``` 276 | 用 yum 命令安装下载好的 rpm 包. 277 | ```plain 278 | yum -y install mysql80-community-release-el7-2.noarch.rpm 279 | ``` 280 | 安装 MySQL 服务器. 281 | ```plain 282 | yum -y install mysql-community-server 283 | ``` 284 | 这一步由于要下载安装文件, 可能会花一些时间. 安装完成后就会覆盖掉之前的 mariadb. 285 | 当出现如下图所示的内容,则代表 MySQL 就安装完成了. 286 | 287 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0050.png) 288 | 289 | ### 1.3.2 MySQL 数据库设置 290 | 291 | 启动 MySQL 292 | 293 | ```plain 294 | systemctl start mysqld.service 295 | ``` 296 | 查看 MySQL 运行状态, Active 后面的状态代表启功服务后为 active (running), 停止后为 inactive (dead), 运行状态如图: 297 | ```plain 298 | systemctl status mysqld.service 299 | ``` 300 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0051.png) 301 | 302 | 重新启动 Mysql 和停止 Mysql 的命令如下: 303 | 304 | ```plain 305 | service mysqld restart #重新启动 Mysql 306 | systemctl stop mysqld.service #停止 Mysql 307 | ``` 308 | 此时 MySQL 已经开始正常运行, 不过要想进入 MySQL 还得先找出此时 root 用户的密码, 通过如下命令可以在日志文件中找出密码: 309 | 为了加强安全性, MySQL8.0 为 root 用户随机生成了一个密码, 在 error log 中, 关于 error log 的位置, 如果安装的是 RPM 包, 则默认是/var/log/mysqld.log.  只有启动过一次 mysql 才可以查看临时密码 310 | 311 | 使用命令: 312 | 313 | ```plain 314 | grep 'temporary password' /var/log/mysqld.log 315 | ``` 316 | 查看初始的随机密码: 317 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0052.png) 318 | 319 | 登录 root 用户 320 | 321 | ```plain 322 | mysql -u root -p 323 | ``` 324 | 然后输入上述查到的初始密码. 登录后还不能做任何查询或建库操作, 因为 MySQL 默认必须修改初始的随机密码之后才能操作数据库,否则会报错: 325 | 326 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0053.png) 327 | 328 | 修改密码为"123456", 注意结尾要有分号, 表示语句的结束. 329 | 330 | ```plain 331 | ALTER USER 'root'@'localhost' IDENTIFIED BY '123456'; 332 | ``` 333 | 这里有个问题, 新密码设置的时候如果设置的过于简单会报错: 334 | 335 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0054.png) 336 | 337 | 原因是因为 MySQL 有密码设置的规范, 具体是与 validate_password_policy 的值有关: 338 | 339 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch00541.png) 340 | 341 | MySQL 完整的初始密码规则可以通过如下命令查看: 342 | 343 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0055.png) 344 | 345 | 密码的长度是由 validate_password_length 决定的, 而 validate_password_length 的计算公式是: 346 | 347 | ```plain 348 | validate_password_length = validate_password_number_count + validate_password_special_char_count + (2 * validate_password_mixed_case_count) 349 | ``` 350 | 如果想要设置简单的密码必须要修改约束, 修改两个全局参数: 351 | * **validate_password_policy**代表密码策略, 默认是 1:符合长度, 且必须含有数字, 小写或大写字母, 特殊字符. 设置为 0 判断密码的标准就基于密码的长度了. 一定要先修改两个参数再修改密码 352 | ```plain 353 | mysql> set global validate_password.policy=0; 354 | ``` 355 | * **validate_password_length**代表密码长度, 最小值为 4 356 | ```plain 357 | mysql> set global validate_password.length=4; 358 | ``` 359 | 修改完,如图 360 | 361 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0056.png) 362 | 363 | 此时密码就可以设置的很简单, 例如 1234 之类的. 到此数据库的密码设置就完成了. 364 | 365 | 但此时还有一个问题, 就是因为安装了 Yum Repository, 以后每次 yum 操作都会自动更新, 如不需要更新, 可以把这个 yum 卸载掉: 366 | 367 | ```plain 368 | [root@localhost ~]# yum -y remove mysql80-community-release-el7-2.noarch 369 | ``` 370 | 371 | 在 CentOS 中 MySQL 的主要配置所在的目录: 372 | 373 | ```plain 374 | 1 /etc/my.cnf 这是 mysql 的主配置文件 375 | 2 /var/lib/mysql mysql 数据库的数据库文件存放位置 376 | 3 /var/log mysql 数据库的日志输出存放位置 377 | ``` 378 | 一些可能会用到的设置: 379 | 380 | 设置表名为大小写不敏感: 381 | 382 | 1.用root帐号登录后, 使用命令 383 | 384 | ```plain 385 | systemctl stop mysqld.service 386 | ``` 387 | 停止MySQL数据库服务,修改vi /etc/my.cnf,在[mysqld]下面添加 388 | ```plain 389 | lower_case_table_names=1 390 | ``` 391 | 这里的参数 0 表示区分大小写,1 表示不区分大小写. 392 | 2.做好数据备份,然后使用下述命令删除数据库数据(删除后, 数据库将恢复到刚安装的状态) 393 | 394 | ```plain 395 | rm -rf /var/lib/mysql 396 | ``` 397 | 3.重启数据库 ,此时数据库恢复到初始状态. 398 | ```plain 399 | service mysql start 400 | ``` 401 | 4.重复安装时的操作, 查找临时密码 402 | ```plain 403 | grep 'temporary password' /var/log/mysqld.log 404 | ``` 405 | 5.修改密码. 密码8位以上, 大小写符号数据. 如想要使用简单密码, 需按照上述安装流程中的步骤进行操作. 406 | ```plain 407 | ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '****';update user set host = "%" where user='root'; 408 | ``` 409 | 6.刷新MySQL的系统权限相关表 410 | ```plain 411 | FLUSH PRIVILEGES; 412 | ``` 413 | 此时, MySQL的表名的大小写不再敏感. 414 | ### 1.3.3 设置远程连接: 415 | 416 | 如果你想要在另外一台电脑上连接 centos 上安装的 MySQL, 那么还需要一些其他的设置. 417 | 418 | 首先需要将 MySQL 设置为可以远程连接,设置 mysql 库的 user 表中帐号的 host 为%, %表示可以从任意 ip 连接 mysql, 为了安全性, 也可以设置为你自己所用于连接 centos 上 MySQL 的电脑所使用的 IP. 419 | 420 | 其次, MYSQL 8.0 内新增加 mysql_native_password 函数,通过更改这个函数密码来进行远程连接. 421 | 422 | 例如,更改 root 用户的 native_password 密码 423 | 424 | ```plain 425 | ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY'MyPass@123'; 426 | ``` 427 | 接下来为 centos 的防火墙开启 MySQL 所使用的 3306 端口,并重新加载防火墙: 428 | ```plain 429 | firewall-cmd --zone=public --add-port=3306/tcp --permanent 430 | firewall-cmd --reload 431 | ``` 432 | 完成上述设置后, 重新启动 MySQL 服务: 433 | ```plain 434 | service mysqld restart #重新启动 Mysql 435 | ``` 436 | 最后, 在另外一台电脑上, 使用下一节介绍的各类客户端工具进行连接测试. 437 | # 2. 连接 MySQL 并执行 SQL 查询 438 | 439 | 在安装成功MySQL后, 我们可以通过开始菜单->控制面板->管理工具->服务中查找并开启或关闭MySQL服务. 开启服务后, MySQL Server将以后台服务的形式在你的电脑上运行. 如果想要进行查询, 还需要使用命令行工具或者其他更加友好的应用程序连接到MySQL服务. 440 | 441 | ## 442 | ## 2.0 使用命令行方式连接MySQL服务 443 | 444 | 连接数据库的最基本的⽅式, 是使用命令⾏. 以win10为例, 在完成 MySQL 服务的安装后, 在开始菜单找到刚才安装好的 MySQL 8.0 命令⾏⼯具,单击即可打开: 445 | 446 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0057.png) 447 | 448 | 输⼊你在安装过程中为root用户设置的密码即可连接到数据库, 看到如下界⾯, 表示数据库安装成功,并且你已经使用命令行连接到了数据库(图中红框表示数据库版本), 在最后的 "mysql>" 后即可输入SQL命令执行各种数据库操作. 449 | 450 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0058.png) 451 | 452 | 但是使用命令行在做数据查询时, 在查询结果的显示和导出方面有诸多不便, 特别是当我们对 SQL 查询不熟练的时候, 这种方式不利于我们进行查询语句的修改和调试. 因此本教程将选择查询界面更加友好的客户端工具(使用MySQL Workbench)来连接数据库, 这种通过命令行连接的方式暂时不再使用. 453 | 454 | >常见的可用于连接MySQL数据库并进行查询等操作的管理工具包括开源软件 MySQL Workbench, HeidiSQL和DBeaver, 以及商业软件Navicat(有免费版和14天试用版),SQLyog(有免费的社区版)和DataGrip等等. 455 | ## 456 | ## 2.1 使用 MySQL Workbench 连接 MySQL 457 | 458 | MySQL Workbench 是 MySQL 官方的客户端工具, 支持windows, macOS和Linux. 对于windows用户, 我们在安装 MySQL 的时候由于选择的是完整安装模式, 因此也同时安装了这个工具, 对于macOS的用户, 可以在[https://dev.mysql.com/downloads/workbench/](https://dev.mysql.com/downloads/workbench/)选择macOS版本进行下载安装. MySQL Workbench 是一款功能强大的数据库管理工具, 它既可以用于设计数据库, 也可以用于连接数据库进行查询, 我们这个课程主要使用它的连接数据库进行查询的功能. 459 | 460 | 如果你使用的是windows 7 操作系统, 打开 MySQL Workbench 后, 会有如下提示: 461 | 462 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0059.png) 463 | 464 | 这是说 MySQL 不再维护win7系统下的MySQL Workbench, 但并不影响使用. 打开MySQL Workbench后, 使用快捷键 ctrl+u,或者点击菜单栏里的 Database->Connect to Database, 进入数据库连接的设置界面, 如下图所示: 465 | 466 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0060.png) 467 | 468 | 然后如下图红框中设置连接本机的 MySQL8.0, 输入密码并点击 OK: 469 | 470 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0061.png) 471 | 472 | 如果弹出如下对话框,表示 MySQL 服务器设置为对于表名和列名的大小写敏感, 但由于 windows 系统默认的是大小写不敏感, 因此当表名或列名有大写字母时, 即使写的 SELECT 语句中正确地使用了大写的表名, 程序也无法正确执行. 这时候建议大家在开始学习查询之前,把表名逐一更改为小写. 473 | 474 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0062.png) 475 | 476 | 打开后的界⾯ 477 | 478 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0063.png) 479 | 480 | 在中间的编辑器里, 就可以写 SQL 查询了. 481 | 482 | 下一次打开软件时, 可以直接点击保存的数据库连接, 不需要先进行设置后再连接了: 483 | 484 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0064.png) 485 | 486 | ## 2.2 [选学]使用 HeidiSQL 连接 MySQL 487 | 488 | HeidiSQL 是一款功能非常强大的开源免费的数据库客户端软件, 采用 Delphi 语言开发, 支持 Windows 操作系统. 支持 MySQL、Postgresql、MariaDB、Percona Server 和微软的 SQL Server, 官网下载地址:[https://www.heidisql.com/download.php](https://www.heidisql.com/download.php), 下载 portable 版本后, 解压缩就可以使用. 489 | 490 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0065.png) 491 | 492 | 点击文件夹中的 heidisql.exe, 在弹出对话框里点击"新建", 然后填写密码, 再点击"打开"即可连接到本机上安装的 MySQL 数据库. 493 | 494 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0066.png) 495 | 496 | 软件的主界面如图所示: 497 | 498 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0067.png) 499 | 500 | ## 2.3 [选学]使用 DBeaver 连接 MySQL 501 | 502 | DBeaver 是一款基于 JAV 开发的**免费和开源(GPL)**的通用数据库管理工具和 SQL 客户端, 提供windows, macOS和Linux全平台支持, 能够连接包括 MySQL, PostgreSQL, Oracle, DB2, MSSQL, Sybase, Mimer, HSQLDB, Derby 等主流数据库软件在内的绝大多数兼容 JDBC 驱动的数据库. DBeaver 提供一个图形界面用来查看数据库结构、执行 SQL 查询和脚本, 浏览和导出数据, 处理 BLOB/CLOB 数据, 修改数据库结构等等. 503 | 504 | 由于是开源软件, 大家可直接从官网([https://dbeaver.io/](https://dbeaver.io/))下载, 安装完成后, 打开软件, 点击"文件"菜单下的"新建连接"图标, 并选择 MySQL: 505 | 506 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0068.png) 507 | 508 | 然后点击下一步: 509 | 510 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0069.png) 511 | 512 | 在下方弹出的设置窗口中, "服务器地址"使用默认的localhost, "数据库"暂时留空, 然后在下方填入自己设置的密码, 最后点击测试连接. 513 | 514 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0070.png) 515 | 516 | 本次学习主要使用一个新建的 shop 数据库, 但因为相关数据我们还没导入(建库建表及数据导入的脚本在本章第三节),因此数据库这里先留空. 等下一步导入数据后, 再进一步修改连接参数. 517 | 518 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0071.png) 519 | 520 | 首次连接时会提示需要下载驱动程序, 521 | 522 | 完成驱动程序的下载后, 再次点击"测试连接",如果弹出如下对话框, 则表示连接成功: 523 | 524 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0072.png) 525 | 526 | 点击确定并保存连接后, 以后就可以直接双击这个连接进行数据库连接了. 如果需要保存多个数据库连接, 可以使用快捷键 F2 或选中当前连接并点击鼠标右键后选择"重命名"为当前连接起一个便于识别的名称. 527 | 528 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0073.png) 529 | 530 | 接下来就可以开始写你的第一个 SQL 语句了: 如上图这样,选中刚刚保存的连接, 鼠标右键选第一个按钮"SQL 编辑器", 或者直接使用快捷键 F3, 就会打开一个 SQL 编辑器, 然后就可以在这里编写 SQL 语句了. 531 | 532 | 例如我们可以使用如下语句完成本教程所使用的示例数据库的创建: 533 | 534 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0074.png) 535 | 536 | 注意, 在使用创建数据库的语句时, 是无需在红框中选中数据库的, 但其他所有的创建表,导入数据, 和最常用的查询语句, 都需要选中相应的数据库. 在执行上述语句后, 我们可以回到连接设置里, 把默认数据库连接改为刚才创建的 shop. 537 | 538 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch00/ch0075.png) 539 | 540 | ## 2.4 [选学]使用 Navicat 连接 MySQL 541 | 542 | Navicat 包含了一系列的功能强大的数据库管理软件, 主要有: 完整功能版的 Navicat Premium, 以及专门用于MySQL数据库管理的 Navicat for MySQL, 用于PostgreSQL数据库管理的 Navicat forPostgreSQL, 用于SQL Server数据库管理的 Navicat for SQL Server, 用于Oracle数据库管理的 Navicat for Oracle, 等等, 但它提供的免费的版本 Navicat Lite 已足够本次课程使用, 除此之外, 上述的其他软件均为收费软件. 543 | 544 | >注: 545 | >Navicat 官网已经不再提供 Navicat Lite 的下载了, 但可以通过搜索引擎找到 Navicat Lite  的历史版本的下载链接. 此外, 也可以从 Navicat 官网下载 Navicat Premium 或 Navicat for MySQL 的14天试用版. 546 | ## 2.5 [选学]使用 SQLyog 连接 MySQL 547 | 548 | SQLyog 是业界著名的 Webyog 公司出品的一款简洁高效、功能强大的图形化 MySQL 数据库管理工具. SQLyog 的企业版是收费软件, 但该软件也提供了社区版供大家使用, 虽然在功能上有些限制, 但对于本课程已经足够用了. SQLyog 社区版的下载地址为[https://github.com/webyog/sqlyog-community/wiki/Downloads](https://github.com/webyog/sqlyog-community/wiki/Downloads) 549 | 550 | 551 | ## 2.6 [选学]DataGrip的安装和连接MySQL 552 | 553 | DataGrip是大名鼎鼎的 JetBrains 出品的数据库工具, 支持windows, macOS和Linux操作系统. 554 | 555 | 556 | 1. 创建学习用的数据库 557 | 558 | 根据《SQL基础教程》提供的MySQL版本的数据库,数据表的创建以及数据导入的代码, 经过一些修改, 创建了一份 sql 脚本, 运行该脚本可以一步到位地创建本文档所需的数据库shop及其中所有的表,并插入本教程所需要的所有数据 559 | 560 | 由于本教程聚焦于面向初学者介绍SQL查询, 对于数据库的创建, 表的创建和数据导入, 以及数据更新, 暂时不做深入介绍,有兴趣和需要的读者可参考《SQL基础教程》1-4,1-5,以及第四章. 561 | 562 | 下述SQL脚本可用于创建本教程所使用的示例数据库shop以及数据库中表的创建和数据的插入. 563 | 564 | 见《附录3 - shop.sql》 565 | 566 | >SQL 脚本的一些要点-- v 9.08 567 | >>0.存储引擎使用 InnoDB, 字符集改为 utf8mb4 以更好地支持中文. 568 | >1.所有表名所使用的英文字母都改为小写(后续章节中,SQL 查询中的表名也需要相应修改为小写) 569 | >2.所有列名所使用的英文字母确认为小写(后续章节中,SQL 查询中的列名也需要相应修改为小写) 570 | >3.存在问题的数据, 例如 inventoryproduct 表的 inventory_id 列应为 P 开头的, 已修正为正确的数据. 571 | >4.需测试 SQL 脚本在命令行及各个客户端中是否能被正确执行. 572 | >* MySQL Workbench 已测试通过(在win10 使用 MySQL Workbench 8.0.21) 573 | >* DBeaver 已测试通过(使用"执行 SQL 脚本(CTR+x)") (在win10 使用 DBeaver7.2.0) 574 | >* HeidiSQL 已测试通过(在win10 使用HeidiSQL 11.0.0) 575 | >* navicat 已测试通过(在win10&win7 使用 navicat premium 15.0.17) 576 | >* sqlyog 已测试通过(在win10 使用 SQLyog 12.09) 577 | >* 命令行 win10 下测试未通过. 插入中文数据时提示" Data too long for column 'product_name' at row 1" 578 | # 579 | 580 | 581 | -------------------------------------------------------------------------------- /Task01:初识数据库.md: -------------------------------------------------------------------------------- 1 | 本章主要讲解数据库安装和数据库基本介绍,考虑易用性及普及度,本课程采取mysql进行教学。 2 | 3 | # 1.1 初识数据库 4 | 5 | 数据库是将大量数据保存起来,通过计算机加工而成的可以进行高效访问的数据集合。该数据集合称为数据库(Database,DB)。用来管理数据库的计算机系统称为数据库管理系统(Database Management System,DBMS)。 6 | 7 | ### 1.1.1 DBMS的种类 8 | 9 | DBMS 主要通过数据的保存格式(数据库的种类)来进行分类,现阶段主要有以下 5 种类型. 10 | 11 | - 层次数据库(Hierarchical Database,HDB) 12 | 13 | - 关系数据库(Relational Database,RDB) 14 | 15 | - Oracle Database:甲骨文公司的RDBMS 16 | - SQL Server:微软公司的RDBMS 17 | - DB2:IBM公司的RDBMS 18 | - PostgreSQL:开源的RDBMS 19 | - MySQL:开源的RDBMS 20 | 21 | 如上是5种具有代表性的RDBMS,其特点是由行和列组成的二维表来管理数据,这种类型的 DBMS 称为关系数据库管理系统(Relational Database Management System,RDBMS)。 22 | 23 | - 面向对象数据库(Object Oriented Database,OODB) 24 | 25 | - XML数据库(XML Database,XMLDB) 26 | 27 | - 键值存储系统(Key-Value Store,KVS),举例:MongoDB 28 | 29 | 本课程将向大家介绍使用 SQL 语言的数据库管理系统,也就是关系数据库管理系统(RDBMS)的操作方法。 30 | 31 | ### 1.1.2 RDBMS的常见系统结构 32 | 33 | 使用 RDBMS 时,最常见的系统结构就是客户端 / 服务器类型(C/S类型)这种结构(图 1-3) 34 | 35 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch01/ch01.01%E7%B3%BB%E7%BB%9F%E7%BB%93%E6%9E%84.jpg) 36 | 37 | # 1.2 初识 SQL 38 | 39 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch01/ch01.02%E8%A1%A8%E7%9A%84%E7%A4%BA%E4%BE%8B.jpg) 40 | 41 | 数据库中存储的表结构类似于excel中的行和列,在数据库中,行称为**记录**,它相当于一条记录,列称为**字段**,它代表了表中存储的数据项目。 42 | 43 | 行和列交汇的地方称为单元格,一个单元格中只能输入一条记录。 44 | 45 | SQL是为操作数据库而开发的语言。国际标准化组织(ISO)为 SQL 制定了相应的标准,以此为基准的SQL 称为标准 SQL。 46 | 47 | 完全基于标准 SQL 的 RDBMS 很少,通常需要根据不同的 RDBMS 来编写特定的 SQL 语句,原则上,本课程介绍的是标准 SQL 的书写方式。 48 | 49 | 根据对 RDBMS 赋予的指令种类的不同,SQL 语句可以分为以下三类. 50 | 51 | * DDL 52 | 53 | DDL(Data Definition Language,数据定义语言) 用来创建或者删除存储数据用的数据库以及数据库中的表等对象。DDL 包含以下几种指令。 54 | 55 | 56 | 57 | - CREATE : 创建数据库和表等对象 58 | 59 | - DROP : 删除数据库和表等对象 60 | 61 | - ALTER : 修改数据库和表等对象的结构 62 | 63 | * DML 64 | 65 | 66 | 67 | DML(Data Manipulation Language,数据操纵语言) 用来查询或者变更表中的记录。DML 包含以下几种指令。 68 | 69 | - SELECT :查询表中的数据 70 | 71 | - INSERT :向表中插入新数据 72 | 73 | - UPDATE :更新表中的数据 74 | 75 | - DELETE :删除表中的数据 76 | 77 | * DCL 78 | 79 | DCL(Data Control Language,数据控制语言) 用来确认或者取消对数据库中的数据进行的变更。除此之外,还可以对 RDBMS 的用户是否有权限操作数据库中的对象(数据库表等)进行设定。DCL 包含以下几种指令。 80 | 81 | - COMMIT : 确认对数据库中的数据进行的变更 82 | 83 | - ROLLBACK : 取消对数据库中的数据进行的变更 84 | 85 | - GRANT : 赋予用户操作权限 86 | 87 | - REVOKE : 取消用户的操作权限 88 | 89 | 90 | 实际使用的 SQL 语句当中有 90% 属于 DML,本书同样会以 DML 为中心进行讲解。 91 | 92 | ### 1.2.1 SQL的基本书写规则 93 | 94 | * SQL语句要以分号( ; )结尾 95 | * SQL 不区分关键字的大小写,但是插入到表中的数据是区分大小写的 96 | * win 系统默认不区分表名及字段名的大小写 97 | * linux / mac 默认严格区分表名及字段名的大小写 98 | * 本教程已统一调整表名及字段名的为小写,以方便初学者学习使用。·· 99 | * 常数的书写方式是固定的 100 | 101 | 'abc', 1234, '26 Jan 2010', '10/01/26', '2010-01-26'...... 102 | 103 | * 单词需要用半角空格或者换行来分隔 104 | 105 | SQL 语句的单词之间需使用半角空格或换行符来进行分隔,且不能使用全角空格作为单词的分隔符,否则会发生错误,出现无法预期的结果。 106 | 107 | 请大家认真查阅《附录1 - SQL 语法规范》,养成规范的书写习惯。 108 | 109 | 110 | 111 | ### 1.2.2 数据库的创建( CREATE DATABASE 语句) 112 | 113 | 语法: 114 | 115 | ```sql 116 | CREATE DATABASE < 数据库名称 > ; 117 | ``` 118 | 创建本课程使用的数据库 119 | ```sql 120 | CREATE DATABASE shop; 121 | ``` 122 | ### 1.2.3 表的创建( CREATE TABLE 语句) 123 | 124 | 语法: 125 | 126 | ```sql 127 | CREATE TABLE < 表名 > 128 | ( < 列名 1> < 数据类型 > < 该列所需约束 > , 129 |   < 列名 2> < 数据类型 > < 该列所需约束 > , 130 |   < 列名 3> < 数据类型 > < 该列所需约束 > , 131 |   < 列名 4> < 数据类型 > < 该列所需约束 > , 132 |   . 133 |   . 134 |   . 135 |   < 该表的约束 1> , < 该表的约束 2> ,……); 136 | ``` 137 | 创建本课程用到的商品表 138 | 139 | ```sql 140 | CREATE TABLE product 141 | (product_id CHAR(4) NOT NULL, 142 |  product_name VARCHAR(100) NOT NULL, 143 |  product_type VARCHAR(32) NOT NULL, 144 |  sale_price INTEGER , 145 |  purchase_price INTEGER , 146 |  regist_date DATE , 147 |  PRIMARY KEY (product_id)); 148 | ``` 149 | 150 | ### 1.2.4 命名规则 151 | 152 | * 只能使用半角英文字母、数字、下划线(_)作为数据库、表和列的名称 153 | * 名称必须以半角英文字母开头 154 | 155 | 表1-3 商品表和 product 表列名的对应关系 156 | 157 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch01/ch01.03%E5%95%86%E5%93%81%E8%A1%A8%E5%92%8C%E5%88%97%E5%90%8D%E5%AF%B9%E5%BA%94%E5%85%B3%E7%B3%BB.png) 158 | 159 | ### 1.2.5 数据类型的指定 160 | 161 | 数据库创建的表,所有的列都必须指定数据类型,每一列都不能存储与该列数据类型不符的数据。 162 | 163 | 四种最基本的数据类型 164 | 165 | * INTEGER 型 166 | 167 | 用来指定存储整数的列的数据类型(数字型),不能存储小数。 168 | 169 | 170 | 171 | * CHAR 型 172 | 173 | 用来存储定长字符串,当列中存储的字符串长度达不到最大长度的时候,使用半角空格进行补足,由于会浪费存储空间,所以一般不使用。 174 | 175 | * VARCHAR 型 176 | 177 | 用来存储可变长度字符串,定长字符串在字符数未达到最大长度时会用半角空格补足,但可变长字符串不同,即使字符数未达到最大长度,也不会用半角空格补足。 178 | 179 | * DATE 型 180 | 181 | 用来指定存储日期(年月日)的列的数据类型(日期型)。 182 | 183 | ### 1.2.6 约束的设置 184 | 185 | 约束是除了数据类型之外,对列中存储的数据进行限制或者追加条件的功能。 186 | 187 | `NOT NULL`是非空约束,即该列必须输入数据。 188 | 189 | `PRIMARY KEY`是主键约束,代表该列是唯一值,可以通过该列取出特定的行的数据。 190 | 191 | ### 1.2.7 表的删除和更新 192 | 193 | * 删除表的语法: 194 | ```sql 195 | DROP TABLE < 表名 > ; 196 | ``` 197 | * 删除 product 表 198 | 199 | 需要特别注意的是,删除的表是无法恢复的,只能重新插入,请执行删除操作时要特别谨慎。 200 | 201 | ```sql 202 | DROP TABLE product; 203 | ``` 204 | - 添加列的 ALTER TABLE 语句 205 | 206 | ```sql 207 | ALTER TABLE < 表名 > ADD COLUMN < 列的定义 >; 208 | ``` 209 | - 添加一列可以存储100位的可变长字符串的 product_name_pinyin 列 210 | 211 | ```sql 212 | ALTER TABLE product ADD COLUMN product_name_pinyin VARCHAR(100); 213 | ``` 214 | - 删除列的 ALTER TABLE 语句 215 | 216 | ```sql 217 | ALTER TABLE < 表名 > DROP COLUMN < 列名 >; 218 | ``` 219 | - 删除 product_name_pinyin 列 220 | 221 | ```sql 222 | ALTER TABLE product DROP COLUMN product_name_pinyin; 223 | ``` 224 | ALTER TABLE 语句和 DROP TABLE 语句一样,执行之后无法恢复。误添的列可以通过 ALTER TABLE 语句删除,或者将表全部删除之后重新再创建。 225 | 【扩展内容】 226 | 227 | * 清空表内容 228 | ```sql 229 | TRUNCATE TABLE TABLE_NAME; 230 | ``` 231 | 优点:相比`drop / delete`,`truncate`用来清除数据时,速度最快。 232 | * 数据的更新 233 | 234 | 基本语法: 235 | 236 | ```sql 237 | UPDATE <表名> 238 | SET <列名> = <表达式> [, <列名2>=<表达式2>...];   239 | WHERE <条件>;  -- 可选,非常重要。 240 | ORDER BY 子句; --可选 241 | LIMIT 子句; --可选 242 | ``` 243 | **使用 update 时要注意添加 where 条件,否则将会将所有的行按照语句修改** 244 | 245 | ```sql 246 | -- 修改所有的注册时间 247 | UPDATE product 248 | SET regist_date = '2009-10-10';   249 | -- 仅修改部分商品的单价 250 | UPDATE product 251 | SET sale_price = sale_price * 10 252 | WHERE product_type = '厨房用具';   253 | ``` 254 | 使用 UPDATE 也可以将列更新为 NULL(该更新俗称为NULL清空)。此时只需要将赋值表达式右边的值直接写为 NULL 即可。 255 | 256 | ```sql 257 | -- 将商品编号为0008的数据(圆珠笔)的登记日期更新为NULL   258 | UPDATE product 259 | SET regist_date = NULL 260 | WHERE product_id = '0008';   261 | ``` 262 | 和 INSERT 语句一样, UPDATE 语句也可以将 NULL 作为一个值来使用。 263 | **但是,只有未设置 NOT NULL 约束和主键约束的列才可以清空为NULL。**如果将设置了上述约束的列更新为 NULL,就会出错,这点与INSERT 语句相同。 264 | 265 | 多列更新 266 | 267 | UPDATE 语句的 SET 子句支持同时将多个列作为更新对象。 268 | 269 | ```sql 270 | -- 基础写法,一条UPDATE语句只更新一列 271 | UPDATE product 272 | SET sale_price = sale_price * 10 273 | WHERE product_type = '厨房用具'; 274 | UPDATE product 275 | SET purchase_price = purchase_price / 2 276 | WHERE product_type = '厨房用具';   277 | ``` 278 | 该写法可以得到正确结果,但是代码较为繁琐。可以采用合并的方法来简化代码。 279 | 280 | ```sql 281 | -- 合并后的写法 282 | UPDATE product 283 | SET sale_price = sale_price * 10, 284 | purchase_price = purchase_price / 2 285 | WHERE product_type = '厨房用具';   286 | ``` 287 | 需要明确的是,SET 子句中的列不仅可以是两列,还可以是三列或者更多。 288 | 289 | ### 1.2.8 向 product 表中插入数据 290 | 291 | 为了学习 `INSERT` 语句用法,我们首先创建一个名为 productins 的表,建表语句如下: 292 | ```sql 293 | CREATE TABLE productins 294 | (product_id CHAR(4) NOT NULL, 295 | product_name VARCHAR(100) NOT NULL, 296 | product_type VARCHAR(32) NOT NULL, 297 | sale_price INTEGER DEFAULT 0, 298 | purchase_price INTEGER , 299 | regist_date DATE , 300 | PRIMARY KEY (product_id)); 301 | ``` 302 | 303 | 基本语法: 304 | 305 | ```sql 306 | INSERT INTO <表名> (列1, 列2, 列3, ……) VALUES (值1, 值2, 值3, ……);   307 | ``` 308 | 对表进行全列 INSERT 时,可以省略表名后的列清单。这时 VALUES子句的值会默认按照从左到右的顺序赋给每一列。 309 | 310 | ```sql 311 | -- 包含列清单 312 | INSERT INTO productins (product_id, product_name, product_type, sale_price, purchase_price, regist_date) VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15'); 313 | -- 省略列清单 314 | INSERT INTO productins VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15');   315 | ``` 316 | 原则上,执行一次 INSERT 语句会插入一行数据。插入多行时,通常需要循环执行相应次数的 INSERT 语句。其实很多 RDBMS 都支持一次插入多行数据 317 | 318 | ```sql 319 | -- 通常的INSERT 320 | INSERT INTO productins VALUES ('0002', '打孔器', '办公用品', 500, 320, '2009-09-11'); 321 | INSERT INTO productins VALUES ('0003', '运动T恤', '衣服', 4000, 2800, NULL); 322 | INSERT INTO productins VALUES ('0004', '菜刀', '厨房用具', 3000, 2800, '2009-09-20'); 323 | -- 多行INSERT ( DB2、SQL、SQL Server、 PostgreSQL 和 MySQL多行插入) 324 | INSERT INTO productins VALUES ('0002', '打孔器', '办公用品', 500, 320, '2009-09-11'), 325 | ('0003', '运动T恤', '衣服', 4000, 2800, NULL), 326 | ('0004', '菜刀', '厨房用具', 3000, 2800, '2009-09-20');   327 | -- Oracle中的多行INSERT 328 | INSERT ALL INTO productins VALUES ('0002', '打孔器', '办公用品', 500, 320, '2009-09-11') 329 | INTO productins VALUES ('0003', '运动T恤', '衣服', 4000, 2800, NULL) 330 | INTO productins VALUES ('0004', '菜刀', '厨房用具', 3000, 2800, '2009-09-20') 331 | SELECT * FROM DUAL;   332 | -- DUAL是Oracle特有(安装时的必选项)的一种临时表A。因此“SELECT *FROM DUAL” 部分也只是临时性的,并没有实际意义。   333 | ``` 334 | INSERT 语句中想给某一列赋予 NULL 值时,可以直接在 VALUES子句的值清单中写入 NULL。想要插入 NULL 的列一定不能设置 NOT NULL 约束。 335 | 336 | ```sql 337 | INSERT INTO productins (product_id, product_name, product_type, sale_price, purchase_price, regist_date) VALUES ('0006', '叉子', '厨房用具', 500, NULL, '2009-09-20');   338 | ``` 339 | 还可以向表中插入默认值(初始值)。可以通过在创建表的CREATE TABLE 语句中设置DEFAULT约束来设定默认值。 340 | 341 | ```sql 342 | CREATE TABLE productins 343 | (product_id CHAR(4) NOT NULL, 344 | (略) 345 | sale_price INTEGER 346 | (略) DEFAULT 0, -- 销售单价的默认值设定为0; 347 | PRIMARY KEY (product_id));   348 | ``` 349 | 可以使用INSERT … SELECT 语句从其他表复制数据。 350 | ```sql 351 | -- 将商品表中的数据复制到商品复制表中 352 | INSERT INTO productcopy (product_id, product_name, product_type, sale_price, purchase_price, regist_date) 353 | SELECT product_id, product_name, product_type, sale_price, purchase_price, regist_date 354 | FROM Product;   355 | ``` 356 | * 本课程用表插入数据sql如下: 357 | ```sql 358 | - DML :插入数据 359 | STARTTRANSACTION; 360 | INSERT INTO product VALUES('0001', 'T恤衫', '衣服', 1000, 500, '2009-09-20'); 361 | INSERT INTO product VALUES('0002', '打孔器', '办公用品', 500, 320, '2009-09-11'); 362 | INSERT INTO product VALUES('0003', '运动T恤', '衣服', 4000, 2800, NULL); 363 | INSERT INTO product VALUES('0004', '菜刀', '厨房用具', 3000, 2800, '2009-09-20'); 364 | INSERT INTO product VALUES('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15'); 365 | INSERT INTO product VALUES('0006', '叉子', '厨房用具', 500, NULL, '2009-09-20'); 366 | INSERT INTO product VALUES('0007', '擦菜板', '厨房用具', 880, 790, '2008-04-28'); 367 | INSERT INTO product VALUES('0008', '圆珠笔', '办公用品', 100, NULL, '2009-11-11'); 368 | COMMIT; 369 | ``` 370 | 371 | # 练习题 372 | 373 | ## 1.1 374 | 375 | 编写一条 CREATE TABLE 语句,用来创建一个包含表 1-A 中所列各项的表 Addressbook (地址簿),并为 regist_no (注册编号)列设置主键约束 376 | 377 | 表1-A 表 Addressbook (地址簿)中的列 378 | 379 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch01/ch01.04%E4%B9%A0%E9%A2%981.png) 380 | 381 | 382 | ## 1.2 383 | 384 | 假设在创建练习1.1中的 Addressbook 表时忘记添加如下一列 postal_code (邮政编码)了,请把此列添加到 Addressbook 表中。 385 | 386 | 列名 : postal_code 387 | 388 | 数据类型 :定长字符串类型(长度为 8) 389 | 390 | 约束 :不能为 NULL 391 | 392 | 393 | 394 | ## 1.3 395 | 396 | 编写 SQL 语句来删除 Addressbook 表。 397 | 398 | ## 1.4 399 | 400 | 编写 SQL 语句来恢复删除掉的 Addressbook 表。 401 | -------------------------------------------------------------------------------- /Task02:基础查询与排序.md: -------------------------------------------------------------------------------- 1 | # 2.1 SELECT语句基础 2 | 3 | ## 2.1.1 从表中选取数据 4 | 5 | ### SELECT语句 6 | 7 | 从表中选取数据时需要使用SELECT语句,也就是只从表中选出(SELECT)必要数据的意思。通过SELECT语句查询并选取出必要数据的过程称为匹配查询或查询(query)。 8 | 9 | 基本SELECT语句包含了SELECT和FROM两个子句(clause)。示例如下: 10 | 11 | ```sql 12 | SELECT <列名>, 13 | FROM <表名>; 14 | ``` 15 | 其中,SELECT子句中列举了希望从表中查询出的列的名称,而FROM子句则指定了选取出数据的表的名称。 16 | ## 2.1.2 从表中选取符合条件的数据 17 | 18 | ### WHERE语句 19 | 20 | 当不需要取出全部数据,而是选取出满足“商品种类为衣服”“销售单价在1000日元以上”等某些条件的数据时,使用WHERE语句。 21 | 22 | SELECT 语句通过WHERE子句来指定查询数据的条件。在WHERE 子句中可以指定“某一列的值和这个字符串相等”或者“某一列的值大于这个数字”等条件。执行含有这些条件的SELECT语句,就可以查询出只符合该条件的记录了。 23 | 24 | ```sql 25 | SELECT <列名>, …… 26 | FROM <表名> 27 | WHERE <条件表达式>; 28 | ``` 29 | 比较下面两者输出结果的不同: 30 | ```sql 31 | -- 用来选取product type列为衣服’的记录的SELECT语句 32 | SELECT product_name, product_type 33 | FROM product 34 | WHERE product_type = '衣服'; 35 | -- 也可以选取出不是查询条件的列(条件列与输出列不同) 36 | SELECT product_name 37 | FROM product 38 | WHERE product_type = '衣服'; 39 | ``` 40 | ## 41 | ## 2.1.3 相关法则 42 | 43 | * 星号(*)代表全部列的意思。 44 | * SQL中可以随意使用换行符,不影响语句执行(但不可插入空行)。 45 | * 设定汉语别名时需要使用双引号(")括起来。 46 | * 在SELECT语句中使用DISTINCT可以删除重复行。 47 | * 注释是SQL语句中用来标识说明或者注意事项的部分。分为1行注释"-- "和多行注释两种"/* */"。 48 | ```sql 49 | -- 想要查询出全部列时,可以使用代表所有列的星号(*)。 50 | SELECT * 51 | FROM <表名>; 52 | -- SQL语句可以使用AS关键字为列设定别名(用中文时需要双引号(“”))。 53 | SELECT product_id As id, 54 | product_name As name, 55 | purchase_price AS "进货单价" 56 | FROM product; 57 | -- 使用DISTINCT删除product_type列中重复的数据 58 | SELECT DISTINCT product_type 59 | FROM product; 60 | ``` 61 | # 62 | # 2.2 算术运算符和比较运算符 63 | 64 | ## 2.2.1 算术运算符 65 | 66 | SQL语句中可以使用的四则运算的主要运算符如下: 67 | 68 | |含义|运算符| 69 | |:----|:----| 70 | |加法|+| 71 | |减法|-| 72 | |乘法|*| 73 | |除法|/| 74 | 75 | ## 76 | ## 2.2.2 比较运算符 77 | 78 | ```sql 79 | -- 选取出sale_price列为500的记录 80 | SELECT product_name, product_type 81 | FROM product 82 | WHERE sale_price = 500; 83 | ``` 84 | SQL常见比较运算符如下: 85 | |运算符|含义| 86 | |:----|:----| 87 | |=|和~相等| 88 | |<>|和~不相等| 89 | |>=|大于等于~| 90 | |>|大于~| 91 | |<=|小于等于~| 92 | |<|小于~| 93 | 94 | ## 95 | ## 2.2.3 常用法则 96 | 97 | * SELECT子句中可以使用常数或者表达式。 98 | * 使用比较运算符时一定要注意不等号和等号的位置。 99 | * 字符串类型的数据原则上按照字典顺序进行排序,不能与数字的大小顺序混淆。 100 | * 希望选取NULL记录时,需要在条件表达式中使用IS NULL运算符。希望选取不是NULL的记录时,需要在条件表达式中使用IS NOT NULL运算符。 101 | 102 | 相关代码如下: 103 | 104 | ```sql 105 | -- SQL语句中也可以使用运算表达式 106 | SELECT product_name, sale_price, sale_price * 2 AS "sale_price x2" 107 | FROM product; 108 | -- WHERE子句的条件表达式中也可以使用计算表达式 109 | SELECT product_name, sale_price, purchase_price 110 | FROM product 111 | WHERE sale_price-purchase_price >= 500; 112 | /* 对字符串使用不等号 113 | 首先创建chars并插入数据 114 | 选取出大于‘2’的SELECT语句*/ 115 | -- DDL:创建表 116 | CREATE TABLE chars 117 | (chr CHAR(3)NOT NULL, 118 | PRIMARY KEY(chr)); 119 | -- 选取出大于'2'的数据的SELECT语句('2'为字符串) 120 | SELECT chr 121 | FROM chars 122 | WHERE chr > '2'; 123 | -- 选取NULL的记录 124 | SELECT product_name, purchase_price 125 | FROM product 126 | WHERE purchase_price IS NULL; 127 | -- 选取不为NULL的记录 128 | SELECT product_name, purchase_price 129 | FROM product 130 | WHERE purchase_price IS NOT NULL; 131 | ``` 132 | # 133 | # 2.3 逻辑运算符 134 | 135 | ## 2.3.1 NOT运算符 136 | 137 | 想要表示“不是……”时,除了前文的<>运算符外,还存在另外一个表示否定、使用范围更广的运算符:NOT。 138 | 139 | NOT不能单独使用,如下例: 140 | 141 | ```sql 142 | -- 选取出销售单价大于等于1000日元的记录 143 | SELECT product_name, product_type, sale_price 144 | FROM product 145 | WHERE sale_price >= 1000; 146 | -- 向代码清单2-30的查询条件中添加NOT运算符 147 | SELECT product_name, product_type, sale_price 148 | FROM product 149 | WHERE NOT sale_price >= 1000; 150 | ``` 151 | ## 152 | ## 2.3.2 AND运算符和OR运算符 153 | 154 | 当希望同时使用多个查询条件时,可以使用AND或者OR运算符。 155 | 156 | AND 相当于“并且”,类似数学中的取交集; 157 | 158 | OR 相当于“或者”,类似数学中的取并集。 159 | 160 | 如下图所示: 161 | 162 | AND运算符工作效果图 163 | 164 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch02/ch02.01and.png) 165 | 166 | OR运算符工作效果图 167 | 168 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch02/ch02.02or.png) 169 | 170 | ### 通过括号优先处理 171 | 172 | 如果要查找这样一个商品,该怎么处理? 173 | 174 | >“商品种类为办公用品”并且“登记日期是 2009 年 9 月 11 日或者 2009 年 9 月 20 日” 175 | >理想结果为“打孔器”,但当你输入以下信息时,会得到错误结果 176 | ```sql 177 | -- 将查询条件原封不动地写入条件表达式,会得到错误结果 178 | SELECT product_name, product_type, regist_date 179 | FROM product 180 | WHERE product_type = '办公用品' 181 | AND regist_date = '2009-09-11' 182 | OR regist_date = '2009-09-20'; 183 | ``` 184 | 错误的原因是**是 AND 运算符优先于 OR 运算符**,想要优先执行OR运算,可以使用**括号**: 185 | ```sql 186 | -- 通过使用括号让OR运算符先于AND运算符执行 187 | SELECT product_name, product_type, regist_date 188 | FROM product 189 | WHERE product_type = '办公用品' 190 | AND ( regist_date = '2009-09-11' 191 | OR regist_date = '2009-09-20'); 192 | ``` 193 | ## 194 | ## 2.3.3 真值表 195 | 196 | 复杂运算时该怎样理解? 197 | 198 | 当碰到条件较复杂的语句时,理解语句含义并不容易,这时可以采用**真值表**来梳理逻辑关系。 199 | 200 | 什么是真值? 201 | 202 | 本节介绍的三个运算符 NOT、AND 和 OR 称为逻辑运算符。这里所说的逻辑就是对真值进行操作的意思。**真值**就是值为真(TRUE)或假 (FALSE)其中之一的值。 203 | 204 | 例如,对于 sale_price >= 3000 这个查询条件来说,由于 product_name 列为 '运动 T 恤' 的记录的 sale_price 列的值是 2800,因此会返回假(FALSE),而 product_name 列为 '高压锅' 的记录的sale_price 列的值是 5000,所以返回真(TRUE)。 205 | 206 | **AND 运算符**两侧的真值都为真时返回真,除此之外都返回假。 207 | 208 | **OR 运算符**两侧的真值只要有一个不为假就返回真,只有当其两侧的真值都为假时才返回假。 209 | 210 | **NOT运算符**只是单纯的将真转换为假,将假转换为真。 211 | 212 | 真值表 213 | 214 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch02/ch02.03true.png) 215 | 216 | 查询条件为P AND(Q OR R)的真值表 217 | 218 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch02/ch02.04true2.png) 219 | 220 | ### 含有NULL时的真值 221 | 222 | NULL的真值结果既不为真,也不为假,因为并不知道这样一个值。 223 | 224 | 那该如何表示呢? 225 | 226 | 这时真值是除真假之外的第三种值——**不确定**(UNKNOWN)。一般的逻辑运算并不存在这第三种值。SQL 之外的语言也基本上只使用真和假这两种真值。与通常的逻辑运算被称为二值逻辑相对,只有 SQL 中的逻辑运算被称为三值逻辑。 227 | 228 | 三值逻辑下的AND和OR真值表为: 229 | 230 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch02/ch02.05true3.png) 231 | 232 | ## 233 | ## 练习题-第一部分 234 | 235 | ### 2.1 236 | 237 | 编写一条SQL语句,从product(商品)表中选取出“登记日期(regist在2009年4月28日之后”的商品,查询结果要包含product name和regist_date两列。 238 | 239 | ### 240 | ### 2.2 241 | 242 | 请说出对product 表执行如下3条SELECT语句时的返回结果。 243 | 244 | ① 245 | 246 | ```sql 247 | SELECT * 248 | FROM product 249 | WHERE purchase_price = NULL; 250 | ``` 251 | ② 252 | ```sql 253 | SELECT * 254 | FROM product 255 | WHERE purchase_price <> NULL; 256 | ``` 257 | ③ 258 | ```sql 259 | SELECT * 260 | FROM product 261 | WHERE product_name > NULL; 262 | ``` 263 | ### 264 | ### 2.3 265 | 266 | 代码清单2-22(2-2节)中的SELECT语句能够从product表中取出“销售单价(saleprice)比进货单价(purchase price)高出500日元以上”的商品。请写出两条可以得到相同结果的SELECT语句。执行结果如下所示。 267 | 268 | ```sql 269 | product_name | sale_price | purchase_price 270 | -------------+------------+------------ 271 | T恤衫 |   1000 | 500 272 | 运动T恤 | 4000 | 2800 273 | 高压锅 | 6800 | 5000 274 | ``` 275 | ### 276 | ### 2.4 277 | 278 | 请写出一条SELECT语句,从product表中选取出满足“销售单价打九折之后利润高于100日元的办公用品和厨房用具”条件的记录。查询结果要包括product_name列、product_type列以及销售单价打九折之后的利润(别名设定为profit)。 279 | 280 | 提示:销售单价打九折,可以通过saleprice列的值乘以0.9获得,利润可以通过该值减去purchase_price列的值获得。 281 | 282 | # 2.4 对表进行聚合查询 283 | 284 | ## 2.4.1 聚合函数 285 | 286 | SQL中用于汇总的函数叫做聚合函数。以下五个是最常用的聚合函数: 287 | 288 | * COUNT:计算表中的记录数(行数) 289 | * SUM:计算表中数值列中数据的合计值 290 | * AVG:计算表中数值列中数据的平均值 291 | * MAX:求出表中任意列中数据的最大值 292 | * MIN:求出表中任意列中数据的最小值 293 | 294 | 请沿用第一章的数据,使用以下操作熟练函数: 295 | 296 | ```sql 297 | -- 计算全部数据的行数(包含NULL) 298 | SELECT COUNT(*) 299 | FROM product; 300 | -- 计算NULL以外数据的行数 301 | SELECT COUNT(purchase_price) 302 | FROM product; 303 | -- 计算销售单价和进货单价的合计值 304 | SELECT SUM(sale_price), SUM(purchase_price) 305 | FROM product; 306 | -- 计算销售单价和进货单价的平均值 307 | SELECT AVG(sale_price), AVG(purchase_price) 308 | FROM product; 309 | -- MAX和MIN也可用于非数值型数据 310 | SELECT MAX(regist_date), MIN(regist_date) 311 | FROM product; 312 | ``` 313 | ### 314 | ### 使用聚合函数删除重复值 315 | 316 | ```sql 317 | -- 计算去除重复数据后的数据行数 318 | SELECT COUNT(DISTINCT product_type) 319 | FROM product; 320 | -- 是否使用DISTINCT时的动作差异(SUM函数) 321 | SELECT SUM(sale_price), SUM(DISTINCT sale_price) 322 | FROM product; 323 | ``` 324 | ## 325 | ## 2.4.2 常用法则 326 | 327 | * COUNT函数的结果根据参数的不同而不同。COUNT(*)会得到包含NULL的数据行数,而COUNT(<列名>)会得到NULL之外的数据行数。 328 | * 聚合函数会将NULL排除在外。但COUNT(*)例外,并不会排除NULL。 329 | * MAX/MIN函数几乎适用于所有数据类型的列。SUM/AVG函数只适用于数值类型的列。 330 | * 想要计算值的种类时,可以在COUNT函数的参数中使用DISTINCT。 331 | * 在聚合函数的参数中使用DISTINCT,可以删除重复数据。 332 | # 333 | # 2.5 对表进行分组 334 | 335 | ## 2.5.1 GROUP BY语句 336 | 337 | 之前使用聚合函数都是会整个表的数据进行处理,当你想将进行分组汇总时(即:将现有的数据按照某列来汇总统计),GROUP BY可以帮助你: 338 | 339 | ```sql 340 | SELECT <列名1>,<列名2>, <列名3>, …… 341 | FROM <表名> 342 | GROUP BY <列名1>, <列名2>, <列名3>, ……; 343 | ``` 344 | 看一看是否使用GROUP BY语句的差异: 345 | ```sql 346 | -- 按照商品种类统计数据行数 347 | SELECT product_type, COUNT(*) 348 | FROM product 349 | GROUP BY product_type; 350 | -- 不含GROUP BY 351 | SELECT product_type, COUNT(*) 352 | FROM product 353 | ``` 354 | 按照商品种类对表进行切分 355 | 356 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch02/ch02.06cut.png) 357 | 358 | 这样,GROUP BY 子句就像切蛋糕那样将表进行了分组。在 GROUP BY 子句中指定的列称为**聚合键**或者**分组列**。 359 | 360 | ### 361 | ### 聚合键中包含NULL时 362 | 363 | 将进货单价(purchase_price)作为聚合键举例: 364 | 365 | ```sql 366 | SELECT purchase_price, COUNT(*) 367 | FROM product 368 | GROUP BY purchase_price; 369 | ``` 370 | 此时会将NULL作为一组特殊数据进行处理 371 | ### 372 | ### GROUP BY书写位置 373 | 374 | GROUP BY的子句书写顺序有严格要求,不按要求会导致SQL无法正常执行,目前出现过的子句顺序为: 375 | 376 | 1 SELECT → 2. FROM → 3. WHERE → 4. GROUP BY 377 | 378 | 其中前三项用于筛选数据,GROUP BY对筛选出的数据进行处理 379 | 380 | ### 381 | ### 在WHERE子句中使用GROUP BY 382 | 383 | ```sql 384 | SELECT purchase_price, COUNT(*) 385 | FROM product 386 | WHERE product_type = '衣服' 387 | GROUP BY purchase_price; 388 | ``` 389 | ## 390 | ## 2.5.2 常见错误 391 | 392 | 在使用聚合函数及GROUP BY子句时,经常出现的错误有: 393 | 394 | 1. 在聚合函数的SELECT子句中写了聚合健以外的列 使用COUNT等聚合函数时,SELECT子句中如果出现列名,只能是GROUP BY子句中指定的列名(也就是聚合键)。 395 | 2. 在GROUP BY子句中使用列的别名 SELECT子句中可以通过AS来指定别名,但在GROUP BY中不能使用别名。因为在DBMS中 ,SELECT子句在GROUP BY子句后执行。 396 | 3. 在WHERE中使用聚合函数 原因是聚合函数的使用前提是结果集已经确定,而WHERE还处于确定结果集的过程中,所以相互矛盾会引发错误。 如果想指定条件,可以在SELECT,HAVING(下面马上会讲)以及ORDER BY子句中使用聚合函数。 397 | # 398 | # 2.6 为聚合结果指定条件 399 | 400 | ## 2.6.1 用HAVING得到特定分组 401 | 402 | 将表使用GROUP BY分组后,怎样才能只取出其中两组? 403 | 404 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch02/ch02.07groupby.png) 405 | 406 | 这里WHERE不可行,因为,WHERE子句只能指定记录(行)的条件,而不能用来指定组的条件(例如,“数据行数为 2 行”或者“平均值为 500”等)。 407 | 408 | 可以在GROUP BY后使用HAVING子句。 409 | 410 | HAVING的用法类似WHERE 411 | 412 | ## 413 | ## 2.6.2 HAVING特点 414 | 415 | HAVING子句用于对分组进行过滤,可以使用数字、聚合函数和GROUP BY中指定的列名(聚合键)。 416 | 417 | ```sql 418 | -- 数字 419 | SELECT product_type, COUNT(*) 420 | FROM product 421 | GROUP BY product_type 422 | HAVING COUNT(*) = 2; 423 | -- 错误形式(因为product_name不包含在GROUP BY聚合键中) 424 | SELECT product_type, COUNT(*) 425 | FROM product 426 | GROUP BY product_type 427 | HAVING product_name = '圆珠笔'; 428 | ``` 429 | # 430 | # 2.7 对查询结果进行排序 431 | 432 | ## 2.7.1 ORDER BY 433 | 434 | SQL中的执行结果是随机排列的,当需要按照特定顺序排序时,可已使用**ORDER BY**子句。 435 | 436 | ```sql 437 | SELECT <列名1>, <列名2>, <列名3>, …… 438 | FROM <表名> 439 | ORDER BY <排序基准列1>, <排序基准列2>, …… 440 | ``` 441 | 默认为升序排列,降序排列为DESC 442 | ```sql 443 | -- 降序排列 444 | SELECT product_id, product_name, sale_price, purchase_price 445 | FROM product 446 | ORDER BY sale_price DESC; 447 | -- 多个排序键 448 | SELECT product_id, product_name, sale_price, purchase_price 449 | FROM product 450 | ORDER BY sale_price, product_id; 451 | -- 当用于排序的列名中含有NULL时,NULL会在开头或末尾进行汇总。 452 | SELECT product_id, product_name, sale_price, purchase_price 453 | FROM product 454 | ORDER BY purchase_price; 455 | ``` 456 | ## 457 | ## 2.7.2 ORDER BY中列名可使用别名 458 | 459 | 前文讲GROUP BY中提到,GROUP BY 子句中不能使用SELECT 子句中定义的别名,但是在 ORDER BY 子句中却可以使用别名。为什么在GROUP BY中不可以而在ORDER BY中可以呢? 460 | 461 | 这是因为SQL在使用 HAVING 子句时 SELECT 语句的顺序为: 462 | 463 | FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。 464 | 465 | 其中SELECT的执行顺序在 GROUP BY 子句之后,ORDER BY 子句之前。也就是说,当在ORDER BY中使用别名时,已经知道了SELECT设置的别名存在,但是在GROUP BY中使用别名时还不知道别名的存在,所以不能在ORDER BY中可以使用别名,但是在GROUP BY中不能使用别名 466 | 467 | ## 468 | ## 练习题-第二部分 469 | 470 | ### 2.5 471 | 472 | 请指出下述SELECT语句中所有的语法错误。 473 | 474 | ```sql 475 | SELECT product_id, SUM(product_name) 476 | --本SELECT语句中存在错误。 477 | FROM product 478 | GROUP BY product_type 479 | WHERE regist_date > '2009-09-01'; 480 | ``` 481 | ### 2.6 482 | 483 | 请编写一条SELECT语句,求出销售单价( `sale_price` 列)合计值大于进货单价( `purchase_price` 列)合计值1.5倍的商品种类。执行结果如下所示。 484 | 485 | ```sql 486 | product_type | sum | sum 487 | -------------+------+------ 488 | 衣服 | 5000 | 3300 489 | 办公用品 | 600 | 320 490 | ``` 491 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch02/ch02.08test26.png) 492 | 493 | ### 2.7 494 | 495 | 此前我们曾经使用SELECT语句选取出了product(商品)表中的全部记录。当时我们使用了ORDERBY子句来指定排列顺序,但现在已经无法记起当时如何指定的了。请根据下列执行结果,思考ORDERBY子句的内容。 496 | 497 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch02/ch02.09test27.png) 498 | 499 | -------------------------------------------------------------------------------- /Task03:复杂一点的查询.md: -------------------------------------------------------------------------------- 1 | 之前接触了sql基本的查询用法,接下来介绍一些相对复杂的用法。 2 | 3 | # 3.1 视图 4 | 5 | 我们先来看一个查询语句 6 | 7 | ```sql 8 | SELECT stu_name FROM view_students_info; 9 | ``` 10 | 单从表面上看起来这个语句是和正常的从数据表中查询数据是完全相同的,但其实我们操作的是一个视图。所以从SQL的角度来说操作视图与操作表看起来是完全相同的,那么为什么还会有视图的存在呢?视图到底是什么?视图与表有什么不同呢? 11 | ## 3.1.1 什么是视图 12 | 13 | 视图是一个虚拟的表,不同于直接操作数据表,视图是依据SELECT语句来创建的(会在下面具体介绍),所以操作视图时会根据创建视图的SELECT语句生成一张虚拟表,然后在这张虚拟表上做SQL操作。 14 | 15 | ## 3.1.2 视图与表有什么区别 16 | 17 | 《*sql**基础**教程**第2版*》用一句话非常凝练的概括了视图与表的区别---“是否保存了实际的数据”。所以视图并不是数据库真实存储的数据表,它可以看作是一个窗口,通过这个窗口我们可以看到数据库表中真实存在的数据。所以我们要区别视图和数据表的本质,即视图是基于真实表的一张虚拟的表,其数据来源均建立在真实表的基础上。 18 | 19 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.01view.png) 20 | 21 | *图片来源:《sql基础教程第2版》* 22 | 23 | 下面这句顺口溜也方便大家记忆视图与表的关系:“视图不是表,视图是虚表,视图依赖于表”。 24 | 25 | ## 3.1.3 为什么会存在视图 26 | 27 | 那既然已经有数据表了,为什么还需要视图呢?主要有以下几点原因: 28 | 29 | 1. 通过定义视图可以将频繁使用的SELECT语句保存以提高效率。 30 | 2. 通过定义视图可以使用户看到的数据更加清晰。 31 | 3. 通过定义视图可以不对外公开数据表全部字段,增强数据的保密性。 32 | 4. 通过定义视图可以降低数据的冗余。 33 | ## 3.1.4 如何创建视图 34 | 35 | 说了这么多视图与表的区别,下面我们就一起来看一下如何创建视图吧。 36 | 37 | 创建视图的基本语法如下: 38 | 39 | ```sql 40 | CREATE VIEW <视图名称>(<列名1>,<列名2>,...) AS 41 | ``` 42 | 其中SELECT 语句需要书写在 AS 关键字之后。 SELECT 语句中列的排列顺序和视图中列的排列顺序相同, SELECT 语句中的第 1 列就是视图中的第 1 列, SELECT 语句中的第 2 列就是视图中的第 2 列,以此类推。而且视图的列名是在视图名称之后的列表中定义的。 43 | 需要注意的是视图名在数据库中需要是唯一的,不能与其他视图和表重名。 44 | 45 | 视图不仅可以基于真实表,我们也可以在视图的基础上继续创建视图。 46 | 47 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.02view2.png) 48 | 49 | *图片来源:《sql基础教程第2版》* 50 | 51 | 虽然在视图上继续创建视图的语法没有错误,但是我们还是应该尽量避免这种操作。这是因为对多数 DBMS 来说, 多重视图会降低 SQL 的性能。 52 | 53 | * 注意事项 54 | 55 | 需要注意的是在一般的DBMS中定义视图时不能使用ORDER BY语句。下面这样定义视图是错误的。 56 | 57 | ```sql 58 | CREATE VIEW productsum (product_type, cnt_product) 59 | AS 60 | SELECT product_type, COUNT(*) 61 | FROM product 62 | GROUP BY product_type 63 | ORDER BY product_type; 64 | ``` 65 | 为什么不能使用 ORDER BY 子句呢?这是因为视图和表一样,**数据行都是没有顺序的**。 66 | 67 | *在 MySQL中视图的定义是允许使用 ORDER BY 语句的,但是若从特定视图进行选择,而该视图使用了自己的 ORDER BY 语句,则视图定义中的 ORDER BY 将被忽略。* 68 | 69 | * 基于单表的视图 70 | 71 | 我们在product表的基础上创建一个视图,如下: 72 | 73 | ```sql 74 | CREATE VIEW productsum (product_type, cnt_product) 75 | AS 76 | SELECT product_type, COUNT(*) 77 | FROM product 78 | GROUP BY product_type ; 79 | ``` 80 | 创建的视图如下图所示: 81 | 82 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.03view3.png) 83 | 84 | 85 | * 基于多表的视图 86 | 87 | 我们在product表和shop_product表的基础上创建视图。 88 | 89 | ```sql 90 | CREATE VIEW view_shop_product(product_type, sale_price, shop_name) 91 | AS 92 | SELECT product_type, sale_price, shop_name 93 | FROM product, 94 | shop_product 95 | WHERE product.product_id = shop_product.product_id; 96 | ``` 97 | 创建的视图如下图所示 98 | 99 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.04view4.png) 100 | 101 | 102 | 我们可以在这个视图的基础上进行查询 103 | 104 | ```sql 105 | SELECT sale_price, shop_name 106 | FROM view_shop_product 107 | WHERE product_type = '衣服'; 108 | ``` 109 | 查询结果为: 110 | 111 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.05result.png) 112 | 113 | 114 | ## 3.1.5 如何修改视图结构 115 | 116 | 修改视图结构的基本语法如下: 117 | 118 | ```sql 119 | ALTER VIEW <视图名> AS 120 | ``` 121 | 其中视图名在数据库中需要是唯一的,不能与其他视图和表重名。 122 | 当然也可以通过将当前视图删除然后重新创建的方式达到修改的效果。(对于数据库底层是不是也是这样操作的呢,你可以自己探索一下。) 123 | 124 | * 修改视图 125 | 126 | 我们修改上方的productSum视图为 127 | 128 | ```sql 129 | ALTER VIEW productSum 130 | AS 131 | SELECT product_type, sale_price 132 | FROM Product 133 | WHERE regist_date > '2009-09-11'; 134 | ``` 135 | 此时productSum视图内容如下图所示 136 | 137 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.06productsum.png) 138 | 139 | 140 | ## 3.1.6 如何更新视图内容 141 | 142 | 因为视图是一个虚拟表,所以对视图的操作就是对底层基础表的操作,所以在修改时只有满足底层基本表的定义才能成功修改。 143 | 144 | 对于一个视图来说,如果包含以下结构的任意一种都是不可以被更新的: 145 | 146 | * 聚合函数 SUM()、MIN()、MAX()、COUNT() 等。 147 | * DISTINCT 关键字。 148 | * GROUP BY 子句。 149 | * HAVING 子句。 150 | * UNION 或 UNION ALL 运算符。 151 | * FROM 子句中包含多个表。 152 | 153 | 视图归根结底还是从表派生出来的,因此,如果原表可以更新,那么 视图中的数据也可以更新。反之亦然,如果视图发生了改变,而原表没有进行相应更新的话,就无法保证数据的一致性了。 154 | 155 | * 更新视图 156 | 157 | 因为我们刚刚修改的productSum视图不包括以上的限制条件,我们来尝试更新一下视图 158 | 159 | ```sql 160 | UPDATE productsum 161 | SET sale_price = '5000' 162 | WHERE product_type = '办公用品'; 163 | ``` 164 | 此时我们再查看productSum视图,可以发现数据已经更新了 165 | 166 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.07productsum2.png) 167 | 168 | 此时观察原表也可以发现数据也被更新了 169 | 170 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.08productsumsrc.png) 171 | 172 | 不知道大家看到这个结果会不会有疑问,刚才修改视图的时候是设置product_type='办公用品'的商品的sale_price=5000,为什么原表的数据只有一条做了修改呢? 173 | 174 | 还是因为视图的定义,视图只是原表的一个窗口,所以它修改也只能修改透过窗口能看到的内容。 175 | 176 | **注意:这里虽然修改成功了,但是并不推荐这种使用方式。而且我们在创建视图时也尽量使用限制不允许通过视图来修改表** 177 | 178 | ## 3.1.7 如何删除视图 179 | 180 | 删除视图的基本语法如下: 181 | 182 | ```sql 183 | DROP VIEW <视图名1> [ , <视图名2> …] 184 | ``` 185 | 注意:需要有相应的权限才能成功删除。 186 | * 删除视图 187 | 188 | 我们删除刚才创建的productSum视图 189 | 190 | ```sql 191 | DROP VIEW productSum; 192 | ``` 193 | 如果我们继续操作这个视图的话就会提示当前操作的内容不存在。 194 | # 3.2 子查询 195 | 196 | 我们先来看一个语句 197 | 198 | ```sql 199 | SELECT stu_name 200 | FROM ( 201 | SELECT stu_name, COUNT(*) AS stu_cnt 202 | FROM students_info 203 | GROUP BY stu_age) AS studentSum; 204 | ``` 205 | 这个语句看起来很好理解,其中使用括号括起来的sql语句首先执行,执行成功后再执行外面的sql语句。但是我们上一节提到的视图也是根据SELECT语句创建视图然后在这个基础上再进行查询。那么什么是子查询呢?子查询和视图又有什么关系呢? 206 | ## 3.2.1 什么是子查询 207 | 208 | 子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从 MySQL 4.1 开始引入,在 SELECT 子句中先计算子查询,子查询结果作为外层另一个查询的过滤条件,查询可以基于一个表或者多个表。 209 | 210 | ## 3.2.2 子查询和视图的关系 211 | 212 | 子查询就是将用来定义视图的 SELECT 语句直接用于 FROM 子句当中。其中AS studentSum可以看作是子查询的名称,而且由于子查询是一次性的,所以子查询不会像视图那样保存在存储介质中, 而是在 SELECT 语句执行之后就消失了。 213 | 214 | ## **3.2.3 嵌套子查询** 215 | 216 | 与在视图上再定义视图类似,子查询也没有具体的限制,例如我们可以这样 217 | 218 | ```sql 219 | SELECT product_type, cnt_product 220 | FROM (SELECT * 221 | FROM (SELECT product_type, 222 | COUNT(*) AS cnt_product 223 | FROM product 224 | GROUP BY product_type) AS productsum 225 | WHERE cnt_product = 4) AS productsum2; 226 | ``` 227 | 其中最内层的子查询我们将其命名为productSum,这条语句根据product_type分组并查询个数,第二层查询中将个数为4的商品查询出来,最外层查询product_type和cnt_product两列。 228 | **虽然嵌套子查询可以查询出结果,但是随着子查询嵌套的层数的叠加,SQL语句不仅会难以理解而且执行效率也会很差,所以要尽量避免这样的使用。** 229 | 230 | ## 3.2.4 标量子查询 231 | 232 | 标量就是单一的意思,那么标量子查询也就是单一的子查询,那什么叫做单一的子查询呢? 233 | 234 | 所谓单一就是要求我们执行的SQL语句只能返回一个值,也就是要返回表中具体的**某一行的某一列**。例如我们有下面这样一张表 235 | 236 | ```sql 237 | product_id | product_name | sale_price 238 | ------------+-------------+---------- 239 | 0003 | 运动T恤 | 4000 240 | 0004 | 菜刀 | 3000 241 | 0005 | 高压锅 | 6800 242 | ``` 243 | 那么我们执行一次标量子查询后是要返回类似于,“0004”,“菜刀”这样的结果。 244 | ## 3.2.5 标量子查询有什么用 245 | 246 | 我们现在已经知道标量子查询可以返回一个值了,那么它有什么作用呢? 247 | 248 | 直接这样想可能会有些困难,让我们看几个具体的需求: 249 | 250 | 1. 查询出销售单价高于平均销售单价的商品 251 | 2. 查询出注册日期最晚的那个商品 252 | 253 | 你有思路了吗? 254 | 255 | 让我们看如何通过标量子查询语句查询出销售单价高于平均销售单价的商品。 256 | 257 | ```sql 258 | SELECT product_id, product_name, sale_price 259 | FROM product 260 | WHERE sale_price > (SELECT AVG(sale_price) FROM product); 261 | ``` 262 | 上面的这条语句首先后半部分查询出product表中的平均售价,前面的sql语句在根据WHERE条件挑选出合适的商品。 263 | 由于标量子查询的特性,导致标量子查询不仅仅局限于 WHERE 子句中,通常任何可以使用单一值的位置都可以使用。也就是说, 能够使用常数或者列名的地方,无论是 SELECT 子句、GROUP BY 子句、HAVING 子句,还是 ORDER BY 子句,几乎所有的地方都可以使用。 264 | 265 | 我们还可以这样使用标量子查询: 266 | 267 | ```sql 268 | SELECT product_id, 269 | product_name, 270 | sale_price, 271 | (SELECT AVG(sale_price) 272 | FROM product) AS avg_price 273 | FROM product; 274 | ``` 275 | 你能猜到这段代码的运行结果是什么吗?运行一下看看与你想象的结果是否一致。 276 | ## 3.2.6 关联子查询 277 | 278 | * 什么是关联子查询 279 | 280 | 关联子查询既然包含关联两个字那么一定意味着查询与子查询之间存在着联系。这种联系是如何建立起来的呢? 281 | 282 | 我们先看一个例子: 283 | 284 | ```sql 285 | SELECT product_type, product_name, sale_price 286 | FROM product AS p1 287 | WHERE sale_price > (SELECT AVG(sale_price) 288 | FROM product AS p2 289 | WHERE p1.product_type = p2.product_type 290 | GROUP BY product_type); 291 | ``` 292 | 你能理解这个例子在做什么操作么?先来看一下这个例子的执行结果 293 | 294 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.09case.png) 295 | 296 | 通过上面的例子我们大概可以猜到吗,关联子查询就是通过一些标志将内外两层的查询连接起来起到过滤数据的目的,接下来我们就一起看一下关联子查询的具体内容吧。 297 | 298 | * 关联子查询与子查询的联系 299 | 300 | 还记得我们之前的那个例子么`查询出销售单价高于平均销售单价的商品`,这个例子的SQL语句如下 301 | 302 | ```sql 303 | SELECT product_id, product_name, sale_price 304 | FROM product 305 | WHERE sale_price > (SELECT AVG(sale_price) FROM product); 306 | ``` 307 | 我们再来看一下这个需求`选取出各商品种类中高于该商品种类的平均销售单价的商品`。SQL语句如下: 308 | ```sql 309 | SELECT product_type, product_name, sale_price 310 | FROM product AS p1 311 | WHERE sale_price > (SELECT AVG(sale_price) 312 | FROM product AS p2 313 | WHERE p1.product_type =p2.product_type 314 | GROUP BY product_type); 315 | ``` 316 | 可以看出上面这两个语句的区别吗? 317 | 318 | 在第二条SQL语句也就是关联子查询中我们将外面的product表标记为p1,将内部的product设置为p2,而且通过WHERE语句连接了两个查询。 319 | 320 | 但是如果刚接触的话一定会比较疑惑关联查询的执行过程,这里有一个[博客](https://zhuanlan.zhihu.com/p/41844742)讲的比较清楚。在这里我们简要的概括为: 321 | 322 | 1. 首先执行不带WHERE的主查询 323 | 2. 根据主查询讯结果匹配product_type,获取子查询结果 324 | 3. 将子查询结果再与主查询结合执行完整的SQL语句 325 | 326 | *在子查询中像标量子查询,嵌套子查询或者关联子查询可以看作是子查询的一种操作方式即可。* 327 | 328 | # 小结 329 | 330 | 视图和子查询是数据库操作中较为基础的内容,对于一些复杂的查询需要使用子查询加一些条件语句组合才能得到正确的结果。但是无论如何对于一个SQL语句来说都不应该设计的层数非常深且特别复杂,不仅可读性差而且执行效率也难以保证,所以尽量有简洁的语句来完成需要的功能。 331 | 332 | # 练习题-第一部分 333 | 334 | ## 3.1 335 | 336 | 创建出满足下述三个条件的视图(视图名称为 ViewPractice5_1)。使用 product(商品)表作为参照表,假设表中包含初始状态的 8 行数据。 337 | 338 | * 条件 1:销售单价大于等于 1000 日元。 339 | * 条件 2:登记日期是 2009 年 9 月 20 日。 340 | * 条件 3:包含商品名称、销售单价和登记日期三列。 341 | 342 | 对该视图执行 SELECT 语句的结果如下所示。 343 | 344 | ```sql 345 | SELECT * FROM ViewPractice5_1; 346 | ``` 347 | 执行结果 348 | 349 | ```sql 350 | product_name | sale_price | regist_date 351 | --------------+------------+------------ 352 | T恤衫 |   1000 | 2009-09-20 353 | 菜刀 | 3000 | 2009-09-20 354 | ``` 355 | ## 3.2 356 | 357 | 向习题一中创建的视图 ViewPractice5_1 中插入如下数据,会得到什么样的结果呢? 358 | 359 | ```sql 360 | INSERT INTO ViewPractice5_1 VALUES (' 刀子 ', 300, '2009-11-02'); 361 | ``` 362 | ## 3.3 363 | 364 | 请根据如下结果编写 SELECT 语句,其中 sale_price_all 列为全部商品的平均销售单价。 365 | 366 | ```sql 367 | product_id | product_name | product_type | sale_price | sale_price_all 368 | ------------+-------------+--------------+------------+--------------------- 369 | 0001 | T恤衫 | 衣服 | 1000 | 2097.5000000000000000 370 | 0002 | 打孔器 | 办公用品 | 500 | 2097.5000000000000000 371 | 0003 | 运动T恤 | 衣服 | 4000 | 2097.5000000000000000 372 | 0004 | 菜刀 | 厨房用具 | 3000 | 2097.5000000000000000 373 | 0005 | 高压锅 | 厨房用具 | 6800 | 2097.5000000000000000 374 | 0006 | 叉子 | 厨房用具 | 500 | 2097.5000000000000000 375 | 0007 | 擦菜板 | 厨房用具 | 880 | 2097.5000000000000000 376 | 0008 | 圆珠笔 | 办公用品 | 100 | 2097.5000000000000000 377 | ``` 378 | ## 3.4 379 | 380 | 请根据习题一中的条件编写一条 SQL 语句,创建一幅包含如下数据的视图(名称为AvgPriceByType)。 381 | 382 | ```sql 383 | product_id | product_name | product_type | sale_price | avg_sale_price 384 | ------------+-------------+--------------+------------+--------------------- 385 | 0001 | T恤衫 | 衣服 | 1000 |2500.0000000000000000 386 | 0002 | 打孔器 | 办公用品 | 500 | 300.0000000000000000 387 | 0003 | 运动T恤 | 衣服 | 4000 |2500.0000000000000000 388 | 0004 | 菜刀 | 厨房用具 | 3000 |2795.0000000000000000 389 | 0005 | 高压锅 | 厨房用具 | 6800 |2795.0000000000000000 390 | 0006 | 叉子 | 厨房用具 | 500 |2795.0000000000000000 391 | 0007 | 擦菜板 | 厨房用具 | 880 |2795.0000000000000000 392 | 0008 | 圆珠笔 | 办公用品 | 100 | 300.0000000000000000 393 | ``` 394 | 提示:其中的关键是 avg_sale_price 列。与习题三不同,这里需要计算出的 是各商品种类的平均销售单价。这与使用关联子查询所得到的结果相同。 也就是说,该列可以使用关联子查询进行创建。问题就是应该在什么地方使用这个关联子查询。 395 | # 396 | # 3.3 各种各样的函数 397 | 398 | sql自带了各种各样的函数,极大提高了sql语言的便利性。 399 | 400 | 所谓函数,类似一个黑盒子,你给它一个输入值,它便按照预设的程序定义给出返回值,输入值称为`参数`。 401 | 402 | 函数大致分为如下几类: 403 | 404 | * 算术函数 (用来进行数值计算的函数) 405 | * 字符串函数 (用来进行字符串操作的函数) 406 | * 日期函数 (用来进行日期操作的函数) 407 | * 转换函数 (用来转换数据类型和值的函数) 408 | * 聚合函数 (用来进行数据聚合的函数) 409 | 410 | 函数总个数超过200个,不需要完全记住,常用函数有 30~50 个,其他不常用的函数使用时查阅文档即可。 411 | 412 | ## 413 | ## 3.3.1 算数函数 414 | 415 | * `+ - * /`四则运算在之前的章节介绍过,此处不再赘述。 416 | 417 | 为了演示其他的几个算数函数,在此构造`samplemath`表 418 | 419 | ```sql 420 | -- DDL :创建表 421 | USE shop; 422 | DROP TABLE IF EXISTS samplemath; 423 | CREATE TABLE samplemath 424 | (m float(10,3), 425 | n INT, 426 | p INT); 427 | 428 | -- DML :插入数据 429 | START TRANSACTION; -- 开始事务 430 | INSERT INTO samplemath(m, n, p) VALUES (500, 0, NULL); 431 | INSERT INTO samplemath(m, n, p) VALUES (-180, 0, NULL); 432 | INSERT INTO samplemath(m, n, p) VALUES (NULL, NULL, NULL); 433 | INSERT INTO samplemath(m, n, p) VALUES (NULL, 7, 3); 434 | INSERT INTO samplemath(m, n, p) VALUES (NULL, 5, 2); 435 | INSERT INTO samplemath(m, n, p) VALUES (NULL, 4, NULL); 436 | INSERT INTO samplemath(m, n, p) VALUES (8, NULL, 3); 437 | INSERT INTO samplemath(m, n, p) VALUES (2.27, 1, NULL); 438 | INSERT INTO samplemath(m, n, p) VALUES (5.555,2, NULL); 439 | INSERT INTO samplemath(m, n, p) VALUES (NULL, 1, NULL); 440 | INSERT INTO samplemath(m, n, p) VALUES (8.76, NULL, NULL); 441 | COMMIT; -- 提交事务 442 | -- 查询表内容 443 | SELECT * FROM samplemath; 444 | +----------+------+------+ 445 | | m        | n    | p    | 446 | +----------+------+------+ 447 | |  500.000 |    0 | NULL | 448 | | -180.000 |    0 | NULL | 449 | |     NULL | NULL | NULL | 450 | |     NULL |    7 |    3 | 451 | |     NULL |    5 |    2 | 452 | |     NULL |    4 | NULL | 453 | |    8.000 | NULL |    3 | 454 | |    2.270 |    1 | NULL | 455 | |    5.555 |    2 | NULL | 456 | |     NULL |    1 | NULL | 457 | |    8.760 | NULL | NULL | 458 | +----------+------+------+ 459 | 11 rows in set (0.00 sec) 460 | ``` 461 | * ABS -- 绝对值 462 | 463 | 语法:`ABS( 数值 )` 464 | 465 | ABS 函数用于计算一个数字的绝对值,表示一个数到原点的距离。 466 | 467 | 当 ABS 函数的参数为`NULL`时,返回值也是`NULL`。 468 | 469 | * MOD -- 求余数 470 | 471 | 语法:`MOD( 被除数,除数 )` 472 | 473 | MOD 是计算除法余数(求余)的函数,是 modulo 的缩写。小数没有余数的概念,只能对整数列求余数。 474 | 475 | 注意:主流的 DBMS 都支持 MOD 函数,只有SQL Server 不支持该函数,其使用`%`符号来计算余数。 476 | 477 | * ROUND -- 四舍五入 478 | 479 | 语法:`ROUND( 对象数值,保留小数的位数 )` 480 | 481 | ROUND 函数用来进行四舍五入操作。 482 | 483 | 注意:当参数 **保留小数的位数** 为变量时,可能会遇到错误,请谨慎使用变量。 484 | 485 | ```sql 486 | SELECT m, 487 | ABS(m)ASabs_col , 488 | n, p, 489 | MOD(n, p) AS mod_col, 490 | ROUND(m,1)ASround_colS 491 | FROM samplemath; 492 | +----------+---------+------+------+---------+-----------+ 493 | | m        | abs_col | n    | p    | mod_col | round_col | 494 | +----------+---------+------+------+---------+-----------+ 495 | |  500.000 | 500.000 |    0 | NULL |    NULL |     500.0 | 496 | | -180.000 | 180.000 |    0 | NULL |    NULL |    -180.0 | 497 | |     NULL |    NULL | NULL | NULL |    NULL |      NULL | 498 | |     NULL |    NULL |    7 |    3 |       1 |      NULL | 499 | |     NULL |    NULL |    5 |    2 |       1 |      NULL | 500 | |     NULL |    NULL |    4 | NULL |    NULL |      NULL | 501 | |    8.000 |   8.000 | NULL |    3 |    NULL |       8.0 | 502 | |    2.270 |   2.270 |    1 | NULL |    NULL |       2.3 | 503 | |    5.555 |   5.555 |    2 | NULL |    NULL |       5.6 | 504 | |     NULL |    NULL |    1 | NULL |    NULL |      NULL | 505 | |    8.760 |   8.760 | NULL | NULL |    NULL |       8.8 | 506 | +----------+---------+------+------+---------+-----------+ 507 | 11 rows in set (0.08 sec) 508 | ``` 509 | ## 3.3.2 字符串函数 510 | 511 | 字符串函数也经常被使用,为了学习字符串函数,在此我们构造`samplestr`表。 512 | 513 | ```sql 514 | -- DDL :创建表 515 | USE shop; 516 | DROP TABLE IF EXISTS samplestr; 517 | CREATE TABLE samplestr 518 | (str1 VARCHAR (40), 519 | str2 VARCHAR (40), 520 | str3 VARCHAR (40) 521 | ); 522 | -- DML:插入数据 523 | START TRANSACTION; 524 | INSERT INTO samplestr (str1, str2, str3) VALUES ('opx', 'rt', NULL); 525 | INSERT INTO samplestr (str1, str2, str3) VALUES ('abc', 'def', NULL); 526 | INSERT INTO samplestr (str1, str2, str3) VALUES ('太阳', '月亮', '火星'); 527 | INSERT INTO samplestr (str1, str2, str3) VALUES ('aaa', NULL, NULL); 528 | INSERT INTO samplestr (str1, str2, str3) VALUES (NULL, 'xyz', NULL); 529 | INSERT INTO samplestr (str1, str2, str3) VALUES ('@!#$%', NULL, NULL); 530 | INSERT INTO samplestr (str1, str2, str3) VALUES ('ABC', NULL, NULL); 531 | INSERT INTO samplestr (str1, str2, str3) VALUES ('aBC', NULL, NULL); 532 | INSERT INTO samplestr (str1, str2, str3) VALUES ('abc哈哈', 'abc', 'ABC'); 533 | INSERT INTO samplestr (str1, str2, str3) VALUES ('abcdefabc', 'abc', 'ABC'); 534 | INSERT INTO samplestr (str1, str2, str3) VALUES ('micmic', 'i', 'I'); 535 | COMMIT; 536 | -- 确认表中的内容 537 | SELECT * FROM samplestr; 538 | +-----------+------+------+ 539 | | str1      | str2 | str3 | 540 | +-----------+------+------+ 541 | | opx       | rt   | NULL | 542 | | abc       | def  | NULL | 543 | | 太阳      | 月亮 | 火星 | 544 | | aaa       | NULL | NULL | 545 | | NULL      | xyz  | NULL | 546 | | @!#$%     | NULL | NULL | 547 | | ABC       | NULL | NULL | 548 | | aBC       | NULL | NULL | 549 | | abc哈哈   | abc  | ABC  | 550 | | abcdefabc | abc  | ABC  | 551 | | micmic    | i    | I    | 552 | +-----------+------+------+ 553 | 11 rows in set (0.00 sec) 554 | ``` 555 | * CONCAT -- 拼接 556 | 557 | 语法:`CONCAT(str1, str2, str3)` 558 | 559 | MySQL中使用 CONCAT 函数进行拼接。 560 | 561 | * LENGTH -- 字符串长度 562 | 563 | 语法:`LENGTH( 字符串 )` 564 | 565 | * LOWER -- 小写转换 566 | 567 | LOWER 函数只能针对英文字母使用,它会将参数中的字符串全都转换为小写。该函数不适用于英文字母以外的场合,不影响原本就是小写的字符。 568 | 569 | 类似的, UPPER 函数用于大写转换。 570 | 571 | * REPLACE -- 字符串的替换 572 | 573 | 语法:`REPLACE( 对象字符串,替换前的字符串,替换后的字符串 )` 574 | 575 | * SUBSTRING -- 字符串的截取 576 | 577 | 语法:`SUBSTRING (对象字符串 FROM 截取的起始位置 FOR 截取的字符数)` 578 | 579 | 使用 SUBSTRING 函数 可以截取出字符串中的一部分字符串。截取的起始位置从字符串最左侧开始计算,索引值起始为1。 580 | 581 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.10function.png) 582 | 583 | * **(扩展内容)SUBSTRING_INDEX -- 字符串按索引截取** 584 | 585 | 语法:`SUBSTRING_INDEX (原始字符串, 分隔符,n)` 586 | 587 | 该函数用来获取原始字符串按照分隔符分割后,第 n 个分隔符之前(或之后)的子字符串,支持正向和反向索引,索引起始值分别为 1 和 -1。 588 | 589 | ```sql 590 | SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2); 591 | +------------------------------------------+ 592 | | SUBSTRING_INDEX('www.mysql.com', '.', 2) | 593 | +------------------------------------------+ 594 | | www.mysql                                | 595 | +------------------------------------------+ 596 | 1 row in set (0.00 sec) 597 | SELECT SUBSTRING_INDEX('www.mysql.com', '.', -2); 598 | +-------------------------------------------+ 599 | | SUBSTRING_INDEX('www.mysql.com', '.', -2) | 600 | +-------------------------------------------+ 601 | | mysql.com                                 | 602 | +-------------------------------------------+ 603 | 1 row in set (0.00 sec) 604 | ``` 605 | 获取第1个元素比较容易,获取第2个元素/第n个元素可以采用二次拆分的写法。 606 | ```sql 607 | SELECT SUBSTRING_INDEX('www.mysql.com', '.', 1); 608 | +------------------------------------------+ 609 | | SUBSTRING_INDEX('www.mysql.com', '.', 1) | 610 | +------------------------------------------+ 611 | | www                                      | 612 | +------------------------------------------+ 613 | 1 row in set (0.00 sec) 614 | SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('www.mysql.com', '.', 2), '.', -1); 615 | +--------------------------------------------------------------------+ 616 | | SUBSTRING_INDEX(SUBSTRING_INDEX('www.mysql.com', '.', 2), '.', -1) | 617 | +--------------------------------------------------------------------+ 618 | | mysql                                                              | 619 | +--------------------------------------------------------------------+ 620 | 1 row in set (0.00 sec) 621 | ``` 622 | ## 3.3.3 日期函数 623 | 624 | 不同DBMS的日期函数语法各有不同,本课程介绍一些被标准 SQL 承认的可以应用于绝大多数 DBMS 的函数。特定DBMS的日期函数查阅文档即可。 625 | 626 | * CURRENT_DATE -- 获取当前日期 627 | ```sql 628 | SELECT CURRENT_DATE; 629 | +--------------+ 630 | | CURRENT_DATE | 631 | +--------------+ 632 | | 2020-08-08   | 633 | +--------------+ 634 | 1 row in set (0.00 sec) 635 | ``` 636 | * CURRENT_TIME -- 当前时间 637 | ```sql 638 | SELECT CURRENT_TIME; 639 | +--------------+ 640 | | CURRENT_TIME | 641 | +--------------+ 642 | | 17:26:09     | 643 | +--------------+ 644 | 1 row in set (0.00 sec) 645 | ``` 646 | * CURRENT_TIMESTAMP -- 当前日期和时间 647 | ```sql 648 | SELECT CURRENT_TIMESTAMP; 649 | +---------------------+ 650 | | CURRENT_TIMESTAMP   | 651 | +---------------------+ 652 | | 2020-08-08 17:27:07 | 653 | +---------------------+ 654 | 1 row in set (0.00 sec) 655 | ``` 656 | * EXTRACT -- 截取日期元素 657 | 658 | 语法:`EXTRACT(日期元素 FROM 日期)` 659 | 660 | 使用 EXTRACT 函数可以截取出日期数据中的一部分,例如“年” 661 | 662 | “月”,或者“小时”“秒”等。该函数的返回值并不是日期类型而是数值类型 663 | 664 | ```sql 665 | SELECT CURRENT_TIMESTAMP as now, 666 | EXTRACT(YEAR FROM CURRENT_TIMESTAMP) AS year, 667 | EXTRACT(MONTH FROM CURRENT_TIMESTAMP) AS month, 668 | EXTRACT(DAY FROM CURRENT_TIMESTAMP) AS day, 669 | EXTRACT(HOUR FROM CURRENT_TIMESTAMP) AS hour, 670 | EXTRACT(MINUTE FROM CURRENT_TIMESTAMP) AS MINute, 671 | EXTRACT(SECOND FROM CURRENT_TIMESTAMP) AS second; 672 | +---------------------+------+-------+------+------+--------+--------+ 673 | | now                 | year | month | day  | hour | MINute | second | 674 | +---------------------+------+-------+------+------+--------+--------+ 675 | | 2020-08-08 17:34:38 | 2020 |     8 |    8 |   17 |     34 |     38 | 676 | +---------------------+------+-------+------+------+--------+--------+ 677 | 1 row in set (0.00 sec) 678 | ``` 679 | ## 3.3.4 转换函数 680 | 681 | “转换”这个词的含义非常广泛,在 SQL 中主要有两层意思:一是数据类型的转换,简称为类型转换,在英语中称为`cast`;另一层意思是值的转换。 682 | 683 | * CAST -- 类型转换 684 | 685 | 语法:`CAST(转换前的值 AS 想要转换的数据类型)` 686 | 687 | ```sql 688 | -- 将字符串类型转换为数值类型 689 | SELECT CAST('0001' AS SIGNED INTEGER) AS int_col; 690 | +---------+ 691 | | int_col | 692 | +---------+ 693 | |       1 | 694 | +---------+ 695 | 1 row in set (0.00 sec) 696 | -- 将字符串类型转换为日期类型 697 | SELECT CAST('2009-12-14' AS DATE) AS date_col; 698 | +------------+ 699 | | date_col   | 700 | +------------+ 701 | | 2009-12-14 | 702 | +------------+ 703 | 1 row in set (0.00 sec) 704 | ``` 705 | * COALESCE -- 将NULL转换为其他值 706 | 707 | 语法:`COALESCE(数据1,数据2,数据3……)` 708 | 709 | COALESCE 是 SQL 特有的函数。该函数会返回可变参数 A 中左侧开始第 1个不是NULL的值。参数个数是可变的,因此可以根据需要无限增加。 710 | 711 | 在 SQL 语句中将 NULL 转换为其他值时就会用到转换函数。 712 | 713 | ```sql 714 | SELECT COALESCE(NULL, 11) AS col_1, 715 | COALESCE(NULL, 'hello world', NULL) AS col_2, 716 | COALESCE(NULL, NULL, '2020-11-01') AS col_3; 717 | +-------+-------------+------------+ 718 | | col_1 | col_2       | col_3      | 719 | +-------+-------------+------------+ 720 | |    11 | hello world | 2020-11-01 | 721 | +-------+-------------+------------+ 722 | 1 row in set (0.00 sec) 723 | ``` 724 | # 725 | # 3.4 谓词 726 | 727 | ## 3.4.1 什么是谓词 728 | 729 | 谓词就是返回值为真值的函数。包括`TRUE / FALSE / UNKNOWN`。 730 | 731 | 谓词主要有以下几个: 732 | 733 | * LIKE 734 | * BETWEEN 735 | * IS NULL、IS NOT NULL 736 | * IN 737 | * EXISTS 738 | ## 739 | ## 3.4.2 LIKE谓词 -- 用于字符串的部分一致查询 740 | 741 | 当需要进行字符串的部分一致查询时需要使用该谓词。 742 | 743 | 部分一致大体可以分为前方一致、中间一致和后方一致三种类型。 744 | 745 | 首先我们来创建一张表 746 | 747 | ```sql 748 | -- DDL :创建表 749 | CREATE TABLE samplelike 750 | ( strcol VARCHAR(6) NOT NULL, 751 | PRIMARY KEY (strcol) 752 | samplelike); 753 | -- DML :插入数据 754 | START TRANSACTION; -- 开始事务 755 | INSERT INTO samplelike (strcol) VALUES ('abcddd'); 756 | INSERT INTO samplelike (strcol) VALUES ('dddabc'); 757 | INSERT INTO samplelike (strcol) VALUES ('abdddc'); 758 | INSERT INTO samplelike (strcol) VALUES ('abcdd'); 759 | INSERT INTO samplelike (strcol) VALUES ('ddabc'); 760 | INSERT INTO samplelike (strcol) VALUES ('abddc'); 761 | COMMIT; -- 提交事务 762 | SELECT * FROM samplelike; 763 | +--------+ 764 | | strcol | 765 | +--------+ 766 | | abcdd  | 767 | | abcddd | 768 | | abddc  | 769 | | abdddc | 770 | | ddabc  | 771 | | dddabc | 772 | +--------+ 773 | 6 rows in set (0.00 sec) 774 | ``` 775 | * 前方一致:选取出“dddabc” 776 | 777 | 前方一致即作为查询条件的字符串(这里是“ddd”)与查询对象字符串起始部分相同。 778 | 779 | ```sql 780 | SELECT * 781 | FROM samplelike 782 | WHERE strcol LIKE 'ddd%'; 783 | +--------+ 784 | | strcol | 785 | +--------+ 786 | | dddabc | 787 | +--------+ 788 | 1 row in set (0.00 sec) 789 | ``` 790 | 其中的`%`是代表“零个或多个任意字符串”的特殊符号,本例中代表“以ddd开头的所有字符串”。 791 | * 中间一致:选取出“abcddd”“dddabc”“abdddc” 792 | 793 | 中间一致即查询对象字符串中含有作为查询条件的字符串,无论该字符串出现在对象字 794 | 795 | 符串的最后还是中间都没有关系。 796 | 797 | ```sql 798 | SELECT * 799 | FROM samplelike 800 | WHERE strcol LIKE '%ddd%'; 801 | +--------+ 802 | | strcol | 803 | +--------+ 804 | | abcddd | 805 | | abdddc | 806 | | dddabc | 807 | +--------+ 808 | 3 rows in set (0.00 sec) 809 | ``` 810 | * 后方一致:选取出“abcddd“ 811 | 812 | 后方一致即作为查询条件的字符串(这里是“ddd”)与查询对象字符串的末尾部分相同。 813 | 814 | ```sql 815 | SELECT * 816 | FROM samplelike 817 | WHERE strcol LIKE '%ddd'; 818 | +--------+ 819 | | strcol | 820 | +--------+ 821 | | abcddd | 822 | +--------+ 823 | 1 row in set (0.00 sec) 824 | ``` 825 | 综合如上三种类型的查询可以看出,查询条件最宽松,也就是能够取得最多记录的是`中间一致`。这是因为它同时包含前方一致和后方一致的查询结果。 826 | * `_`下划线匹配任意 1 个字符 827 | 828 | 使用 _(下划线)来代替 %,与 % 不同的是,它代表了“任意 1 个字符”。 829 | 830 | ```sql 831 | SELECT * 832 | FROM samplelike 833 | WHERE strcol LIKE 'abc__'; 834 | +--------+ 835 | | strcol | 836 | +--------+ 837 | | abcdd  | 838 | +--------+ 839 | 1 row in set (0.00 sec) 840 | ``` 841 | ## 842 | ## 3.4.3 BETWEEN谓词 -- 用于范围查询 843 | 844 | 使用 BETWEEN 可以进行范围查询。该谓词与其他谓词或者函数的不同之处在于它使用了 3 个参数。 845 | 846 | ```sql 847 | -- 选取销售单价为100~ 1000元的商品 848 | SELECT product_name, sale_price 849 | FROM product 850 | WHERE sale_price BETWEEN 100 AND 1000; 851 | +--------------+------------+ 852 | | product_name | sale_price | 853 | +--------------+------------+ 854 | | T恤          |       1000 | 855 | | 打孔器       |        500 | 856 | | 叉子         |        500 | 857 | | 擦菜板       |        880 | 858 | | 圆珠笔       |        100 | 859 | +--------------+------------+ 860 | 5 rows in set (0.00 sec) 861 | ``` 862 | BETWEEN 的特点就是结果中会包含 100 和 1000 这两个临界值,也就是闭区间。如果不想让结果中包含临界值,那就必须使用 < 和 >。 863 | ```sql 864 | SELECT product_name, sale_price 865 | FROM product 866 | WHERE sale_price > 100 867 | AND sale_price < 1000; 868 | +--------------+------------+ 869 | | product_name | sale_price | 870 | +--------------+------------+ 871 | | 打孔器       |        500 | 872 | | 叉子         |        500 | 873 | | 擦菜板       |        880 | 874 | +--------------+------------+ 875 | 3 rows in set (0.00 sec) 876 | ``` 877 | ## 878 | ## 3.4.4 IS NULL、 IS NOT NULL -- 用于判断是否为NULL 879 | 880 | 为了选取出某些值为 NULL 的列的数据,不能使用 =,而只能使用特定的谓词IS NULL。 881 | 882 | ```sql 883 | SELECT product_name, purchase_price 884 | FROM product 885 | WHERE purchase_price IS NULL; 886 | +--------------+----------------+ 887 | | product_name | purchase_price | 888 | +--------------+----------------+ 889 | | 叉子         |           NULL | 890 | | 圆珠笔       |           NULL | 891 | +--------------+----------------+ 892 | 2 rows in set (0.00 sec) 893 | ``` 894 | 与此相反,想要选取 NULL 以外的数据时,需要使用IS NOT NULL。 895 | ```sql 896 | SELECT product_name, purchase_price 897 | FROM product 898 | WHERE purchase_price IS NOT NULL; 899 | +--------------+----------------+ 900 | | product_name | purchase_price | 901 | +--------------+----------------+ 902 | | T恤          |            500 | 903 | | 打孔器       |            320 | 904 | | 运动T恤      |           2800 | 905 | | 菜刀         |           2800 | 906 | | 高压锅       |           5000 | 907 | | 擦菜板       |            790 | 908 | +--------------+----------------+ 909 | 6 rows in set (0.00 sec) 910 | ``` 911 | ## 912 | ## 3.4.5 IN谓词 -- OR的简便用法 913 | 914 | 多个查询条件取并集时可以选择使用`or`语句。 915 | 916 | ```sql 917 | -- 通过OR指定多个进货单价进行查询 918 | SELECT product_name, purchase_price 919 | FROM product 920 | WHERE purchase_price = 320 921 | OR purchase_price = 500 922 | OR purchase_price = 5000; 923 | +--------------+----------------+ 924 | | product_name | purchase_price | 925 | +--------------+----------------+ 926 | | T恤          |            500 | 927 | | 打孔器       |            320 | 928 | | 高压锅       |           5000 | 929 | +--------------+----------------+ 930 | 3 rows in set (0.00 sec) 931 | ``` 932 | 虽然上述方法没有问题,但还是存在一点不足之处,那就是随着希望选取的对象越来越多, SQL 语句也会越来越长,阅读起来也会越来越困难。这时, 我们就可以使用IN 谓词 933 | `IN(值1, 值2, 值3, ......)来替换上述 SQL 语句。 934 | 935 | ```sql 936 | SELECT product_name, purchase_price 937 | FROM product 938 | WHERE purchase_price IN (320, 500, 5000); 939 | +--------------+----------------+ 940 | | product_name | purchase_price | 941 | +--------------+----------------+ 942 | | T恤          |            500 | 943 | | 打孔器       |            320 | 944 | | 高压锅       |           5000 | 945 | +--------------+----------------+ 946 | 3 rows in set (0.00 sec) 947 | ``` 948 | 上述语句简洁了很多,可读性大幅提高。 949 | 反之,希望选取出“进货单价不是 320 元、 500 元、 5000 元”的商品时,可以使用否定形式NOT IN来实现。 950 | 951 | ```sql 952 | SELECT product_name, purchase_price 953 | FROM product 954 | WHERE purchase_price NOT IN (320, 500, 5000); 955 | +--------------+----------------+ 956 | | product_name | purchase_price | 957 | +--------------+----------------+ 958 | | 运动T恤      |           2800 | 959 | | 菜刀         |           2800 | 960 | | 擦菜板       |            790 | 961 | +--------------+----------------+ 962 | 3 rows in set (0.00 sec) 963 | ``` 964 | 需要注意的是,在使用IN 和 NOT IN 时是无法选取出NULL数据的。 965 | 实际结果也是如此,上述两组结果中都不包含进货单价为 NULL 的叉子和圆珠笔。 NULL 只能使用 IS NULL 和 IS NOT NULL 来进行判断。 966 | 967 | ## 968 | ## 3.4.6 使用子查询作为IN谓词的参数 969 | 970 | * IN和子查询 971 | 972 | IN 谓词(NOT IN 谓词)具有其他谓词所没有的用法,那就是可以使用子查询作为其参数。我们已经在 5-2 节中学习过了,子查询就是 SQL内部生成的表,因此也可以说“能够将表作为 IN 的参数”。同理,我们还可以说“能够将视图作为 IN 的参数”。 973 | 974 | 在此,我们创建一张新表`shopproduct`显示出哪些商店销售哪些商品。 975 | 976 | ```sql 977 | -- DDL :创建表 978 | DROP TABLE IF EXISTS shopproduct; 979 | CREATE TABLE shopproduct 980 | ( shop_id CHAR(4) NOT NULL, 981 |  shop_name VARCHAR(200) NOT NULL, 982 | product_id CHAR(4) NOT NULL, 983 |   quantity INTEGER NOT NULL, 984 | PRIMARY KEY (shop_id, product_id) -- 指定主键 985 | ); 986 | -- DML :插入数据 987 | START TRANSACTION; -- 开始事务 988 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000A', '东京', '0001', 30); 989 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000A', '东京', '0002', 50); 990 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000A', '东京', '0003', 15); 991 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000B', '名古屋', '0002', 30); 992 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000B', '名古屋', '0003', 120); 993 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000B', '名古屋', '0004', 20); 994 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000B', '名古屋', '0006', 10); 995 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000B', '名古屋', '0007', 40); 996 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000C', '大阪', '0003', 20); 997 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000C', '大阪', '0004', 50); 998 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000C', '大阪', '0006', 90); 999 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000C', '大阪', '0007', 70); 1000 | INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES ('000D', '福冈', '0001', 100); 1001 | COMMIT; -- 提交事务 1002 | SELECT * FROM shopproduct; 1003 | +---------+-----------+------------+----------+ 1004 | | shop_id | shop_name | product_id | quantity | 1005 | +---------+-----------+------------+----------+ 1006 | | 000A    | 东京      | 0001       |       30 | 1007 | | 000A    | 东京      | 0002       |       50 | 1008 | | 000A    | 东京      | 0003       |       15 | 1009 | | 000B    | 名古屋      | 0002       |       30 | 1010 | | 000B    | 名古屋      | 0003       |      120 | 1011 | | 000B    | 名古屋      | 0004       |       20 | 1012 | | 000B    | 名古屋      | 0006       |       10 | 1013 | | 000B    | 名古屋      | 0007       |       40 | 1014 | | 000C    | 大阪      | 0003       |       20 | 1015 | | 000C    | 大阪      | 0004       |       50 | 1016 | | 000C    | 大阪      | 0006       |       90 | 1017 | | 000C    | 大阪      | 0007       |       70 | 1018 | | 000D    | 福冈      | 0001       |      100 | 1019 | +---------+-----------+------------+----------+ 1020 | 13 rows in set (0.00 sec) 1021 | ``` 1022 | 由于单独使用商店编号(shop_id)或者商品编号(product_id)不能区分表中每一行数据 1023 | ,因此指定了 2 列作为主键(primary key)对商店和商品进行组合,用来唯一确定每一行数据。 1024 | 1025 | 假设我么需要取出大阪在售商品的销售单价,该如何实现呢? 1026 | 1027 | 第一步,取出大阪门店的在售商品 `product_id ; 1028 | 1029 | 第二步,取出大阪门店在售商品的销售单价 `sale_price 1030 | 1031 | ```sql 1032 | -- step1:取出大阪门店的在售商品 `product_id` 1033 | SELECT product_id 1034 | FROM shopproduct 1035 | WHERE shop_id = '000C'; 1036 | +------------+ 1037 | | product_id | 1038 | +------------+ 1039 | | 0003       | 1040 | | 0004       | 1041 | | 0006       | 1042 | | 0007       | 1043 | +------------+ 1044 | 4 rows in set (0.00 sec) 1045 | ``` 1046 | 上述语句取出了大阪门店的在售商品编号,接下来,我么可以使用上述语句作为第二步的查询条件来使用了。 1047 | ```sql 1048 | -- step2:取出大阪门店在售商品的销售单价 `sale_price` 1049 | SELECT product_name, sale_price 1050 | FROM product 1051 | WHERE product_id IN (SELECT product_id 1052 | FROM shopproduct 1053 | WHERE shop_id = '000C'); 1054 | +--------------+------------+ 1055 | | product_name | sale_price | 1056 | +--------------+------------+ 1057 | | 运动T恤      |       4000 | 1058 | | 菜刀         |       3000 | 1059 | | 叉子         |        500 | 1060 | | 擦菜板       |        880 | 1061 | +--------------+------------+ 1062 | 4 rows in set (0.00 sec) 1063 | ``` 1064 | 根据第5章学习的知识,子查询是从最内层开始执行的(由内而外),因此,上述语句的子查询执行之后,sql 展开成下面的语句 1065 | ```sql 1066 | -- 子查询展开后的结果 1067 | SELECT product_name, sale_price 1068 | FROM product 1069 | WHERE product_id IN ('0003', '0004', '0006', '0007'); 1070 | +--------------+------------+ 1071 | | product_name | sale_price | 1072 | +--------------+------------+ 1073 | | 运动T恤      |       4000 | 1074 | | 菜刀         |       3000 | 1075 | | 叉子         |        500 | 1076 | | 擦菜板       |        880 | 1077 | +--------------+------------+ 1078 | 4 rows in set (0.00 sec) 1079 | ``` 1080 | 可以看到,子查询转换之后变为 in 谓词用法,你理解了吗? 1081 | 或者,你会疑惑既然 in 谓词也能实现,那为什么还要使用子查询呢?这里给出两点原因: 1082 | 1083 | ①:实际生活中,某个门店的在售商品是不断变化的,使用 in 谓词就需要经常更新 sql 语句,降低了效率,提高了维护成本; 1084 | 1085 | ②:实际上,某个门店的在售商品可能有成百上千个,手工维护在售商品编号真是个大工程。 1086 | 1087 | 使用子查询即可保持 sql 语句不变,极大提高了程序的可维护性,这是系统开发中需要重点考虑的内容。 1088 | 1089 | * NOT IN和子查询 1090 | 1091 | NOT IN 同样支持子查询作为参数,用法和 in 完全一样。 1092 | 1093 | ```sql 1094 | -- NOT IN 使用子查询作为参数,取出未在大阪门店销售的商品的销售单价 1095 | SELECT product_name, sale_price 1096 | FROM product 1097 | WHERE product_id NOT IN (SELECT product_id 1098 | FROM shopproduct 1099 | WHERE shop_id = '000A'); 1100 | +--------------+------------+ 1101 | | product_name | sale_price | 1102 | +--------------+------------+ 1103 | | 菜刀         |       3000 | 1104 | | 高压锅       |       6800 | 1105 | | 叉子         |        500 | 1106 | | 擦菜板       |        880 | 1107 | | 圆珠笔       |        100 | 1108 | +--------------+------------+ 1109 | 5 rows in set (0.00 sec) 1110 | ``` 1111 | ## 1112 | ## 3.4.7 EXIST 谓词 1113 | 1114 | EXIST 谓词的用法理解起来有些难度。 1115 | 1116 | ① EXIST 的使用方法与之前的都不相同 1117 | 1118 | ② 语法理解起来比较困难 1119 | 1120 | ③ 实际上即使不使用 EXIST,基本上也都可以使用 IN(或者 NOT IN)来代替 1121 | 1122 | 这么说的话,还有学习 EXIST 谓词的必要吗?答案是肯定的,因为一旦能够熟练使用 EXIST 谓词,就能体会到它极大的便利性。 1123 | 1124 | 不过,你不用过于担心,本课程介绍一些基本用法,日后学习时可以多多留意 EXIST 谓词的用法,以期能够在达到 SQL 中级水平时掌握此用法。 1125 | 1126 | * EXIST谓词的使用方法 1127 | 1128 | 谓词的作用就是 **“判断是否存在满足某种条件的记录”**。 1129 | 1130 | 如果存在这样的记录就返回真(TRUE),如果不存在就返回假(FALSE)。 1131 | 1132 | EXIST(存在)谓词的主语是“记录”。 1133 | 1134 | 我们继续以 IN和子查询 中的示例,使用 EXIST 选取出大阪门店在售商品的销售单价。 1135 | 1136 | ```sql 1137 | SELECT product_name, sale_price 1138 | FROM product AS p 1139 | WHERE EXISTS (SELECT * 1140 | FROM shopproduct AS sp 1141 | WHERE sp.shop_id = '000C' 1142 | AND sp.product_id = p.product_id); 1143 | +--------------+------------+ 1144 | | product_name | sale_price | 1145 | +--------------+------------+ 1146 | | 运动T恤      |       4000 | 1147 | | 菜刀         |       3000 | 1148 | | 叉子         |        500 | 1149 | | 擦菜板       |        880 | 1150 | +--------------+------------+ 1151 | 4 rows in set (0.00 sec) 1152 | ``` 1153 | * EXIST的参数 1154 | 1155 | 之前我们学过的谓词,基本上都是像“列 LIKE 字符串”或者“ 列 BETWEEN 值 1 AND 值 2”这样需要指定 2 个以上的参数,而 EXIST 的左侧并没有任何参数。因为 EXIST 是只有 1 个参数的谓词。 所以,EXIST 只需要在右侧书写 1 个参数,该参数通常都会是一个子查询。 1156 | 1157 | ```sql 1158 | (SELECT * 1159 | FROM shopproduct AS sp 1160 | WHERE sp.shop_id = '000C' 1161 | AND sp.product_id = p.product_id)   1162 | ``` 1163 | 上面这样的子查询就是唯一的参数。确切地说,由于通过条件“SP.product_id = P.product_id”将 product 表和 shopproduct表进行了联接,因此作为参数的是关联子查询。 EXIST 通常会使用关联子查询作为参数。 1164 | * 子查询中的SELECT * 1165 | 1166 | 由于 EXIST 只关心记录是否存在,因此返回哪些列都没有关系。 EXIST 只会判断是否存在满足子查询中 WHERE 子句指定的条件“商店编号(shop_id)为 '000C',商品(product)表和商店 1167 | 1168 | 商品(shopproduct)表中商品编号(product_id)相同”的记录,只有存在这样的记录时才返回真(TRUE)。 1169 | 1170 | 因此,使用下面的查询语句,查询结果也不会发生变化。 1171 | 1172 | ```sql 1173 | SELECT product_name, sale_price 1174 | FROM product AS p 1175 | WHERE EXISTS (SELECT 1 -- 这里可以书写适当的常数 1176 | FROM shopproduct AS sp 1177 | WHERE sp.shop_id = '000C' 1178 | AND sp.product_id = p.product_id); 1179 | +--------------+------------+ 1180 | | product_name | sale_price | 1181 | +--------------+------------+ 1182 | | 运动T恤      |       4000 | 1183 | | 菜刀         |       3000 | 1184 | | 叉子         |        500 | 1185 | | 擦菜板       |        880 | 1186 | +--------------+------------+ 1187 | 4 rows in set (0.00 sec) 1188 | ``` 1189 | >大家可以把在 EXIST 的子查询中书写 SELECT * 当作 SQL 的一种习惯。 1190 | * 使用NOT EXIST替换NOT IN 1191 | 1192 | 就像 EXIST 可以用来替换 IN 一样, NOT IN 也可以用NOT EXIST来替换。 1193 | 1194 | 下面的代码示例取出,不在大阪门店销售的商品的销售单价。 1195 | 1196 | ```sql 1197 | SELECT product_name, sale_price 1198 | FROM product AS p 1199 | WHERE NOT EXISTS (SELECT * 1200 | FROM shopproduct AS sp 1201 | WHERE sp.shop_id = '000A' 1202 | AND sp.product_id = p.product_id); 1203 | +--------------+------------+ 1204 | | product_name | sale_price | 1205 | +--------------+------------+ 1206 | | 菜刀         |       3000 | 1207 | | 高压锅       |       6800 | 1208 | | 叉子         |        500 | 1209 | | 擦菜板       |        880 | 1210 | | 圆珠笔       |        100 | 1211 | +--------------+------------+ 1212 | 5 rows in set (0.00 sec) 1213 | ``` 1214 | NOT EXIST 与 EXIST 相反,当“不存在”满足子查询中指定条件的记录时返回真(TRUE)。 1215 | # 1216 | # 3.5 CASE 表达式 1217 | 1218 | ## 3.5.1 什么是 CASE 表达式? 1219 | 1220 | CASE 表达式是函数的一种。是 SQL 中数一数二的重要功能,有必要好好学习一下。 1221 | 1222 | CASE 表达式是在区分情况时使用的,这种情况的区分在编程中通常称为(条件)分支。 1223 | 1224 | CASE表达式的语法分为简单CASE表达式和搜索CASE表达式两种。由于搜索CASE表达式包含简单CASE表达式的全部功能。本课程将重点介绍搜索CASE表达式。 1225 | 1226 | 语法: 1227 | 1228 | ```plain 1229 | CASE WHEN <求值表达式> THEN <表达式> 1230 | WHEN <求值表达式> THEN <表达式> 1231 | WHEN <求值表达式> THEN <表达式> 1232 | . 1233 | . 1234 | . 1235 | ELSE <表达式> 1236 | END   1237 | ``` 1238 | 上述语句执行时,依次判断 when 表达式是否为真值,是则执行 THEN 后的语句,如果所有的 when 表达式均为假,则执行 ELSE 后的语句。 1239 | 无论多么庞大的 CASE 表达式,最后也只会返回一个值。 1240 | 1241 | ## 1242 | ## 3.5.2 CASE表达式的使用方法 1243 | 1244 | 假设现在 要实现如下结果: 1245 | 1246 | ```plain 1247 | A :衣服 1248 | B :办公用品 1249 | C :厨房用具   1250 | ``` 1251 | 因为表中的记录并不包含“A : ”或者“B : ”这样的字符串,所以需要在 SQL 中进行添加。并将“A : ”“B : ”“C : ”与记录结合起来。 1252 | * **应用场景1:根据不同分支得到不同列值** 1253 | ```sql 1254 | SELECT  product_name, 1255 | CASE WHEN product_type = '衣服' THEN CONCAT('A : ',product_type) 1256 | WHEN product_type = '办公用品'  THEN CONCAT('B : ',product_type) 1257 | WHEN product_type = '厨房用具'  THEN CONCAT('C : ',product_type) 1258 | ELSE NULL 1259 | END AS abc_product_type 1260 | FROM product; 1261 | +--------------+------------------+ 1262 | | product_name | abc_product_type | 1263 | +--------------+------------------+ 1264 | | T恤          | A : 衣服        | 1265 | | 打孔器       | B : 办公用品    | 1266 | | 运动T恤      | A : 衣服        | 1267 | | 菜刀         | C : 厨房用具    | 1268 | | 高压锅       | C : 厨房用具    | 1269 | | 叉子         | C : 厨房用具    | 1270 | | 擦菜板       | C : 厨房用具    | 1271 | | 圆珠笔       | B : 办公用品    | 1272 | +--------------+------------------+ 1273 | 8 rows in set (0.00 sec) 1274 | ``` 1275 | ELSE 子句也可以省略不写,这时会被默认为 ELSE NULL。但为了防止有人漏读,还是希望大家能够显示地写出 ELSE 子句。 1276 | 此外, CASE 表达式最后的“END”是不能省略的,请大家特别注意不要遗漏。忘记书写 END 会发生语法错误,这也是初学时最容易犯的错误。 1277 | 1278 | * **应用场景2:实现列方向上的聚合** 1279 | 1280 | 通常我们使用如下代码实现行的方向上不同种类的聚合(这里是 sum) 1281 | 1282 | ```sql 1283 | SELECT product_type, 1284 | SUM(sale_price) AS sum_price 1285 | FROM product 1286 | GROUP BY product_type;   1287 | +--------------+-----------+ 1288 | | product_type | sum_price | 1289 | +--------------+-----------+ 1290 | | 衣服         |      5000 | 1291 | | 办公用品     |       600 | 1292 | | 厨房用具     |     11180 | 1293 | +--------------+-----------+ 1294 | 3 rows in set (0.00 sec) 1295 | ``` 1296 | 假如要在列的方向上展示不同种类额聚合值,该如何写呢? 1297 | ```plain 1298 | sum_price_clothes | sum_price_kitchen | sum_price_office 1299 | ------------------+-------------------+----------------- 1300 | 5000 | 11180 | 600   1301 | ``` 1302 | 聚合函数 + CASE WHEN 表达式即可实现该效果 1303 | ```sql 1304 | -- 对按照商品种类计算出的销售单价合计值进行行列转换 1305 | SELECT SUM(CASE WHEN product_type = '衣服' THEN sale_price ELSE 0 END) AS sum_price_clothes, 1306 | SUM(CASE WHEN product_type = '厨房用具' THEN sale_price ELSE 0 END) AS sum_price_kitchen, 1307 | SUM(CASE WHEN product_type = '办公用品' THEN sale_price ELSE 0 END) AS sum_price_office 1308 | FROM product; 1309 | +-------------------+-------------------+------------------+ 1310 | | sum_price_clothes | sum_price_kitchen | sum_price_office | 1311 | +-------------------+-------------------+------------------+ 1312 | |              5000 |             11180 |              600 | 1313 | +-------------------+-------------------+------------------+ 1314 | 1 row in set (0.00 sec) 1315 | ``` 1316 | * **(扩展内容)应用场景3:实现行转列** 1317 | 1318 | 假设有如下图表的结构 1319 | 1320 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.11casewhen1.png) 1321 | 1322 | 计划得到如下的图表结构 1323 | 1324 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch03/ch03.12casewhen2.png) 1325 | 1326 | 聚合函数 + CASE WHEN 表达式即可实现该转换 1327 | 1328 | ```sql 1329 | -- CASE WHEN 实现数字列 score 行转列 1330 | SELECT name, 1331 | SUM(CASE WHEN subject = '语文' THEN score ELSE null END) as chinese, 1332 | SUM(CASE WHEN subject = '数学' THEN score ELSE null END) as math, 1333 | SUM(CASE WHEN subject = '外语' THEN score ELSE null END) as english 1334 | FROM score 1335 | GROUP BY name; 1336 | +------+---------+------+---------+ 1337 | | name | chinese | math | english | 1338 | +------+---------+------+---------+ 1339 | | 张三 | 93 | 88 | 91 | 1340 | | 李四 | 87 | 90 | 77 | 1341 | +------+---------+------+---------+ 1342 | 2 rows in set (0.00 sec) 1343 | ``` 1344 | 上述代码实现了数字列 score 的行转列,也可以实现文本列 subject 的行转列 1345 | ```sql 1346 | -- CASE WHEN 实现文本列 subject 行转列 1347 | SELECT name, 1348 | MAX(CASE WHEN subject = '语文' THEN subject ELSE null END) as chinese, 1349 | MAX(CASE WHEN subject = '数学' THEN subject ELSE null END) as math, 1350 | MIN(CASE WHEN subject = '外语' THEN subject ELSE null END) as english 1351 | FROM score 1352 | GROUP BY name; 1353 | +------+---------+------+---------+ 1354 | | name | chinese | math | english | 1355 | +------+---------+------+---------+ 1356 | | 张三 | 语文 | 数学 | 外语 | 1357 | | 李四 | 语文 | 数学 | 外语 | 1358 | +------+---------+------+---------+ 1359 | 2 rows in set (0.00 sec 1360 | ``` 1361 | 总结: 1362 | * 当待转换列为数字时,可以使用`SUM AVG MAX MIN`等聚合函数; 1363 | * 当待转换列为文本时,可以使用`MAX MIN`等聚合函数 1364 | # 1365 | # 练习题-第二部分 1366 | 1367 | ## 3.5 1368 | 1369 | 运算或者函数中含有 NULL 时,结果全都会变为NULL ?(判断题) 1370 | 1371 | ## 3.6 1372 | 1373 | 对本章中使用的 product(商品)表执行如下 2 条 SELECT 语句,能够得到什么样的结果呢? 1374 | 1375 | ① 1376 | 1377 | ```sql 1378 | SELECT product_name, purchase_price 1379 | FROM product 1380 | WHERE purchase_price NOT IN (500, 2800, 5000); 1381 | ``` 1382 | ② 1383 | ```sql 1384 | SELECT product_name, purchase_price 1385 | FROM product 1386 | WHERE purchase_price NOT IN (500, 2800, 5000, NULL); 1387 | ``` 1388 | ## 3.7 1389 | 1390 | 按照销售单价( sale_price)对练习 3.6 中的 product(商品)表中的商品进行如下分类。 1391 | 1392 | * 低档商品:销售单价在1000日元以下(T恤衫、办公用品、叉子、擦菜板、 圆珠笔) 1393 | * 中档商品:销售单价在1001日元以上3000日元以下(菜刀) 1394 | * 高档商品:销售单价在3001日元以上(运动T恤、高压锅) 1395 | 1396 | 请编写出统计上述商品种类中所包含的商品数量的 SELECT 语句,结果如下所示。 1397 | 1398 | 执行结果 1399 | 1400 | ```sql 1401 | low_price | mid_price | high_price 1402 | ----------+-----------+------------ 1403 | 5 | 1 | 2 1404 | ``` 1405 | ## 1406 | 1407 | -------------------------------------------------------------------------------- /Task04:集合运算.md: -------------------------------------------------------------------------------- 1 | # 4.1 表的加减法 2 | 3 | ## 4.1.1 什么是集合运算 4 | 5 | `集合`在数学领域表示“各种各样的事物的总和”, 在数据库领域表示记录的集合. 具体来说,表、视图和查询的执行结果都是记录的集合, 其中的元素为表或者查询结果中的每一行. 6 | 7 | 在标准 SQL 中, 分别对检索结果使用 `UNION`, `INTERSECT,` `EXCEPT` 来将检索结果进行并,交和差运算, 像`UNION`,`INTERSECT`, `EXCEPT`这种用来进行集合运算的运算符称为集合运算符. 8 | 9 | 以下的文氏图展示了几种集合的基本运算. 10 | 11 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.01.png) 12 | 13 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.02.png) 14 | 15 | [图片来源于网络] 16 | 17 | 在数据库中, 所有的表--以及查询结果--都可以视为集合, 因此也可以把表视为集合进行上述集合运算, 在很多时候, 这种抽象非常有助于对复杂查询问题给出一个可行的思路. 18 | 19 | ## 4.1.2 表的加法--UNION 20 | 21 | ### 4.1.2.1 UNION 22 | 23 | 建表代码及数据导入请使用第一章提供的代码. 24 | 25 | 接下来我们演示UNION的具体用法及查询结果: 26 | 27 | ```sql 28 | SELECT product_id, product_name 29 | FROM Product 30 | UNION 31 | SELECT product_id, product_name 32 | FROM Product2; 33 | ``` 34 | 上述结果包含了两张表中的全部商品. 你会发现,这就是我们在学校学过的集合中的并集运算,通过文氏图会看得更清晰(图 7-1): 35 | 36 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.03union.png) 37 | 38 | 通过观察可以发现,商品编号为“ 0001 ”~“ 0003 ”的 3 条记录在两个表中都存在,因此大家可能会认为结果中会出现重复的记录,但是 **UNION 等集合运算符通常都会除去重复的记录**. 39 | 40 | 上述查询是对不同的两张表进行求并集运算. 对于同一张表, 实际上也是可以进行求并集的. 41 | 42 | **练习题:** 43 | 44 | 假设连锁店想要增加毛利率超过 50%或者售价低于 800 的货物的存货量, 请使用 UNION 对分别满足上述两个条件的商品的查询结果求并集. 45 | 46 | 结果应该类似于: 47 | 48 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.04result.png) 49 | 50 | 51 | 52 | ```sql 53 | -- 参考答案: 54 | SELECT product_id,product_name,product_type 55 |   ,sale_price,purchase_price 56 | FROM PRODUCT 57 | WHERE sale_price<800 58 | 59 | UNION 60 | 61 | SELECT product_id,product_name,product_type 62 |   ,sale_price,purchase_price 63 | FROM PRODUCT 64 | WHERE sale_price>1.5*purchase_price; 65 | ``` 66 | 思考: 如果不使用 UNION 该怎么写查询语句? 67 | 68 | ```sql 69 | -- 参考答案: 70 | SELECT product_id,product_name,product_type 71 |   ,sale_price,purchase_price 72 | FROM PRODUCT 73 | WHERE sale_price < 800 74 | OR sale_price > 1.5 * purchase_price; 75 | ``` 76 | ### 77 | ### 4.1.2.2 UNION 与 OR 谓词 78 | 79 | 对于上边的练习题, 如果你已经正确地写出来查询, 你会发现, 使用 UNION 对两个查询结果取并集, 和在一个查询中使用 WHERE 子句, 然后使用 OR 谓词连接两个查询条件, 能够得到相同的结果. 80 | 81 | 那么是不是就没必要引入 UNION 了呢? 当然不是这样的. 确实, 对于同一个表的两个不同的筛选结果集, 使用 UNION 对两个结果集取并集, 和把两个子查询的筛选条件用 OR 谓词连接, 会得到相同的结果, 但倘若要将两个不同的表中的结果合并在一起, 就不得不使用 UNION 了. 82 | 83 | 而且, 即便是对于同一张表, 有时也会出于查询效率方面的因素来使用 UNION. 84 | 85 | **练习题 :** 86 | 87 | 分别使用 UNION 或者 OR 谓词,找出毛利率不足 30%或毛利率未知的商品. 88 | 89 | 参考答案: 90 | 91 | ```sql 92 | -- 使用 OR 谓词 93 | SELECT *  94 |   FROM Product  95 |  WHERE sale_price / purchase_price < 1.3 96 | OR sale_price / purchase_price IS NULL; 97 | ``` 98 | ```sql 99 | -- 使用 UNION 100 | SELECT *  101 |   FROM Product  102 |  WHERE sale_price / purchase_price < 1.3 103 |   104 | UNION 105 | SELECT *  106 |   FROM Product  107 |  WHERE sale_price / purchase_price IS NULL; 108 | ``` 109 | 110 | ### 4.1.2.3 包含重复行的集合运算 UNION ALL 111 | 112 | 在1.1.1 中我们发现, SQL 语句的 UNION 会对两个查询的结果集进行合并和去重, 这种去重不仅会去掉两个结果集相互重复的, 还会去掉一个结果集中的重复行. 但在实践中有时候需要需要不去重的并集, 在 UNION 的结果中保留重复行的语法其实非常简单,只需要在 UNION 后面添加 ALL 关键字就可以了. 113 | 114 | 例如, 想要知道 Product 和 Product2 中所包含的商品种类及每种商品的数量, 第一步,就需要将两个表的商品种类字段选出来, 然后使用 UNION ALL 进行不去重地合并. 接下来再对两个表的结果按 Product_type 字段分组计数. 115 | 116 | ```sql 117 | -- 保留重复行 118 | SELECT product_id, product_name 119 | FROM Product 120 | UNION ALL 121 | SELECT product_id, product_name 122 | FROM Product2; 123 | ``` 124 | 查询结果如下: 125 | 126 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.05result2.png) 127 | 128 | **练习题:** 129 | 130 | 商店决定对product表中利润低于50%和售价低于1000的商品提价, 请使用UNION ALL 语句将分别满足上述两个条件的结果取并集. 查询结果类似下表: 131 | 132 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.06result3.png) 133 | 134 | 参考答案 135 | 136 | ```sql 137 | SELECT * 138 | FROM Product 139 | WHERE sale_price < 1000 140 | UNION ALL 141 | SELECT * 142 | FROM Product 143 | WHERE sale_price < 1.5 * purchase_price 144 | ``` 145 | ### 4.1.2.4 [扩展阅读]bag 模型与 set 模型 146 | 147 | 在高中数学课上我们就学过, 集合的一个显著的特征就是集合中的元素都是互异的. 当我们把数据库中的表看作是集合的时候, 实际上存在一些问题的: 不论是有意的设计或无意的过失, 很多数据库中的表包含了重复的行. 148 | 149 | Bag 是和 set 类似的一种数学结构, 不一样的地方在于: bag 里面允许存在重复元素, 如果同一个元素被加入多次, 则袋子里就有多个该元素. 150 | 151 | 通过上述 bag 与 set 定义之间的差别我们就发现, 使用 bag 模型来描述数据库中的表在很多时候更加合适. 152 | 153 | 是否允许元素重复导致了 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}. 154 | 155 | ### 156 | ### 4.1.2.5 隐式类型转换 157 | 158 | 通常来说, 我们会把类型完全一致, 并且代表相同属性的列使用 UNION 合并到一起显示, 但有时候, 即使数据类型不完全相同, 也会通过隐式类型转换来将两个类型不同的列放在一列里显示, 例如字符串和数值类型: 159 | 160 | ```sql 161 | SELECT product_id, product_name, '1' 162 |   FROM Product 163 | UNION 164 | SELECT product_id, product_name,sale_price 165 |   FROM Product2; 166 | ``` 167 | 上述查询能够正确执行,得到如下结果: 168 | 169 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.07result4.png) 170 | 171 | **练习题:** 172 | 173 | 使用 SYSDATE()函数可以返回当前日期时间, 是一个日期时间类型的数据, 试测试该数据类型和数值,字符串等类型的兼容性. 174 | 175 | 例如, 以下代码可以正确执行, 说明时间日期类型和字符串,数值以及缺失值均能兼容. 176 | 177 | ```sql 178 | SELECT SYSDATE(), SYSDATE(), SYSDATE() 179 | 180 | UNION 181 | 182 | SELECT 'chars', 123,  null 183 | ``` 184 | 上述代码的查询结果: 185 | 186 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.08result5.png) 187 | 188 | 189 | 190 | ## 4.1.3 MySQL 8.0 不支持交运算INTERSECT 191 | 192 | 集合的交, 就是两个集合的公共部分, 由于集合元素的互异性, 集合的交只需通过文氏图就可以很直观地看到它的意义. 193 | 194 | 虽然集合的交运算在SQL标准中已经出现多年了, 然而很遗憾的是, 截止到 MySQL 8.0 版本, MySQL 仍然不支持 INTERSECT 操作. 195 | 196 | ```sql 197 | SELECT product_id, product_name 198 | FROM Product 199 | 200 | INTERSECT 201 | SELECT product_id, product_name 202 | FROM Product2 203 | ``` 204 | >错误代码:1064 205 | >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 206 | >FROM Product2 207 | ### 208 | ### 4.1.3.1 [扩展阅读]bag 的交运算 209 | 210 | 对于两个 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}. 211 | 212 | ## 4.1.4 差集,补集与表的减法 213 | 214 | 求集合差集的减法运算和实数的减法运算有些不同, 当使用一个集合A减去另一个集合B的时候,对于只存在于集合B而不存在于集合A的元素, 采取直接忽略的策略,因此集合A和B做减法只是将集合A中也同时属于集合B的元素减掉. 215 | 216 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.09except.png) 217 | 218 | ### 219 | ### 4.1.4.1 MySQL 8.0 还不支持 EXCEPT 运算 220 | 221 | MySQL 8.0 还不支持 表的减法运算符 EXCEPT. 不过, 借助第六章学过的NOT IN 谓词, 我们同样可以实现表的减法. 222 | 223 | **练习题****:** 224 | 225 | 找出只存在于Product表但不存在于Product2表的商品. 226 | 227 | ```sql 228 | -- 使用 IN 子句的实现方法 229 | SELECT * 230 | FROM Product 231 | WHERE product_id NOT IN (SELECT product_id 232 |   FROM Product2) 233 | ``` 234 | ### 4.1.4.2 EXCEPT 与 NOT 谓词 235 | 236 | 通过上述练习题的MySQL解法, 我们发现, 使用 NOT IN 谓词, 基本上可以实现和SQL标准语法中的EXCEPT运算相同的效果. 237 | 238 | **练习题:** 239 | 240 | 使用NOT谓词进行集合的减法运算, 求出Product表中, 售价高于2000,但利润低于30%的商品, 结果应该如下表所示. 241 | 242 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.10.png) 243 | 244 | 参考答案: 245 | 246 | ```sql 247 | SELECT * 248 | FROM Product 249 | WHERE sale_price > 2000 250 | AND product_id NOT IN (SELECT product_id 251 | FROM Product 252 | WHERE sale_price<1.3*purchase_price) 253 | ``` 254 | ### 255 | ### 4.1.4.3 EXCEPT ALL 与bag 的差 256 | 257 | 类似于UNION ALL, EXCEPT ALL 也是按出现次数进行减法, 也是使用bag模型进行运算. 258 | 259 | 对于两个 bag, 他们的差运算会按照: 260 | 261 | **1.该元素是否属于作为被减数的 bag,** 262 | 263 | **2.该元素在两个 bag 中的出现次数** 264 | 265 | 这两个方面来进行计算. 只有属于被减数的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}. 266 | 267 | ### 4.1.4.4 INTERSECT 与 AND 谓词 268 | 269 | 对于同一个表的两个查询结果而言, 他们的交INTERSECT实际上可以等价地将两个查询的检索条件用AND谓词连接来实现. 270 | 271 | **练习题:** 272 | 273 | ****使用AND谓词查找product表中利润率高于50%,并且售价低于1500的商品,查询结果如下所示. 274 | 275 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.11.png) 276 | 277 | 参考答案 278 | 279 | ```sql 280 | SELECT * 281 | FROM Product 282 | WHERE sale_price > 1.5 * purchase_price 283 | AND sale_price < 1500 284 | ``` 285 | ## 4.1.5 对称差 286 | 287 | 两个集合A,B的对称差是指那些仅属于A或仅属于B的元素构成的集合. 对称差也是个非常基础的运算, 例如, 两个集合的交就可以看作是两个集合的并去掉两个集合的对称差.上述方法在其他数据库里也可以用来简单地实现表或查询结果的对称差运算: 首先使用UNION求两个表的并集, 然后使用INTERSECT求两个表的交集, 然后用并集减去交集, 就得到了对称差. 288 | 289 | 但由于在MySQL 8.0 里, 由于两个表或查询结果的并不能直接求出来, 因此并不适合使用上述思路来求对称差. 好在还有差集运算可以使用. 从直观上就能看出来, 两个集合的对称差等于 A-B并上B-A, 因此实践中可以用这个思路来求对称差. 290 | 291 | **练习题:** 292 | 293 | 使用Product表和Product2表的对称差来查询哪些商品只在其中一张表, 结果类似于: 294 | 295 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.12.png) 296 | 297 | 提示: 使用 NOT IN 实现两个表的差集. 298 | 299 | **参考答案:** 300 | 301 | ```sql 302 | -- 使用 NOT IN 实现两个表的差集 303 | SELECT * 304 | FROM Product 305 | WHERE product_id NOT IN (SELECT product_id FROM Product2) 306 | UNION 307 | SELECT * 308 | FROM Product2 309 | WHERE product_id NOT IN (SELECT product_id FROM Product) 310 | ``` 311 | ### 312 | ### 4.1.5.1 借助并集和差集迂回实现交集运算 INTERSECT 313 | 314 | 通过观察集合运算的文氏图, 我们发现, 两个集合的交可以看作是两个集合的并去掉两个集合的对称差。 315 | 316 | ## 317 | # 4.2 连结(JOIN) 318 | 319 | 前一节我们学习了 UNION和INTERSECT 等集合运算, 这些集合运算的特征就是以行方向为单位进行操作. 通俗地说, 就是进行这些集合运算时, 会导致记录行数的增减. 使用 UNION 会增加记录行数,而使用 INTERSECT 或者 EXCEPT 会减少记录行数. 320 | 321 | 但这些运算不能改变列的变化, 虽然使用函数或者 CASE表达式等列运算, 可以增加列的数量, 但仍然只能从一张表中提供的基础信息列中获得一些"引申列", 本质上并不能提供更多的信息. 如果想要从多个表获取信息, 例如, 如果我们想要找出某个商店里的衣服类商品的名称,数量及价格等信息, 则必须分别从 ShopProduct 表和 Product 表获取信息. 322 | 323 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.13join.png) 324 | 325 | >注: 326 | >截至目前,本书中出现的示例(除了关联子查询)基本上都是从一张表中选取数据,但实际上,期望得到的数据往往会分散在不同的表之中, 这时候就需要使用连结了. 327 | >之前在学习关联子查询时我们发现, 使用关联子查询也可以从其他表获取信息, 但**连结**更适合从多张表获取信息. 328 | 329 | 连结(JOIN)就是使用某种关联条件(一般是使用相等判断谓词"="), 将其他表中的列添加过来, 进行“添加列”的集合运算. 可以说,连结是 SQL 查询的核心操作, 掌握了连结, 能够从两张甚至多张表中获取列, 能够将过去使用关联子查询等过于复杂的查询简化为更加易读的形式, 以及进行一些更加复杂的查询. 330 | 331 | SQL 中的连结有多种分类方法, 我们这里使用最基础的内连结和外连结的分类方法来分别进行讲解. 332 | 333 | ## 4.2.1 内连结(INNER JOIN) 334 | 335 | 内连结的语法格式是: 336 | 337 | ```sql 338 | -- 内连结 339 | FROM INNER JOIN ON 340 | ``` 341 | 其中 INNER 关键词表示使用了内连结, 至于内连结的涵义, 目前暂时可以不必细究. 342 | 例如, 还是刚才那个问题: 343 | 344 | 找出某个商店里的衣服类商品的名称,数量及价格等信息. 345 | 346 | 我们进一步把这个问题明确化: 347 | 348 | 找出东京商店里的衣服类商品的商品名称,商品价格,商品种类,商品数量信息. 349 | 350 | ### 4.2.1.1 使用内连结从两个表获取信息 351 | 352 | 我们先来分别观察所涉及的表, Product 表保存了商品编号,商品名称,商品种类等信息,这个表可以提供关于衣服种类的衣服的详细信息, 但是不能提供商店信息. 353 | 354 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.14tb.png) 355 | 356 | 我们接下来观察 ShopProduct 表, 这个表里有商店编号名称,商店的商品编号及数量. 但要想获取商品的种类及名称售价等信息,则必须借助于 Product 表. 357 | 358 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.15shopproduct.png) 359 | 360 | 所以问题的关键是, 找出一个类似于"轴"或者"桥梁"的公共列, 将两张表用这个列连结起来. 这就是连结运算所要作的事情. 361 | 362 | 我们来对比一下上述两张表, 可以发现, 商品编号列是一个公共列, 因此很自然的事情就是用这个商品编号列来作为连接的“桥梁”,将Product和ShopProduct这两张表连接起来。 363 | 364 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.16tb73.png) 365 | 366 | >注: 367 | >如果你使用过 excel 的 vlookup 函数, 你会发现这个函数正好也能够实现这个功能. 实际上, 在思路上, 关联子查询更像是 vlookup 函数: 以表 A 为主表, 然后根据表 A 的关联列的每一行的取值,逐个到表 B 中的关联列中去查找取值相等的行. 368 | >当数据量较少时, 这种方式并不会有什么性能问题, 但数据量较大时, 这种方式将会导致较大的计算开销: 对于外部查询返回的每一行数据, 都会向内部的子查询传递一个关联列的值, 然后内部子查询根据传入的值执行一次查询然后返回它的查询结果. 这就使得, 例如外部主查询的返回结果有一万行, 那么子查询就会执行一万次, 这将会带来非常恐怖的时间消耗. 369 | 370 | 我们把上述问题进行分解: 371 | 372 | 首先, 找出每个商店的商店编号, 商店名称, 商品编号, 商品名称, 商品类别, 商品售价,商品数量信息. 373 | 374 | 按照内连结的语法, 在 FROM 子句中使用 INNER JOIN 将两张表连接起来, 并为 ON 子句指定连结条件为 ShopProduct.product_id=Product.product_id, 就得到了如下的查询语句: 375 | 376 | ```sql 377 | SELECT SP.shop_id 378 | ,SP.shop_name 379 | ,SP.product_id 380 |   ,P.product_name 381 | ,P.product_type 382 | ,P.sale_price 383 | ,SP.quantity 384 |   FROM ShopProduct AS SP 385 |  INNER JOIN Product AS P 386 |   ON SP.product_id = P.product_id; 387 | ``` 388 | 在上述查询中, 我们分别为两张表指定了简单的别名, 这种操作在使用连结时是非常常见的, 通过别名会让我们在编写查询时少打很多字, 并且更重要的是, 会让查询语句看起来更加简洁. 389 | 上述查询将会得到如下的结果: 390 | 391 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.17result.png) 392 | 393 | 观察查询结果, 我们看到,这个结果里的列已经包含了所有我们需要的信息. 394 | 395 | 关于内连结,需要注意以下三点: 396 | 397 | **要点一: 进行连结时需要在 FROM 子句中使用多张表.** 398 | 399 | 之前的 FROM 子句中只有一张表, 而这次我们同时使用了 ShopProduct 和 Product 两张表,使用关键字 INNER JOIN 就可以将两张表连结在一起了: 400 | 401 | ```sql 402 | FROM ShopProduct AS SP INNER JOIN Product AS P 403 | ``` 404 | **要点二:必须使用 ON 子句来指定连结条件.** 405 | 406 | 在进行内连结时 ON 子句是必不可少的(大家可以试试去掉上述查询的 ON 子句后会有什么结果). 407 | 408 | ON 子句是专门用来指定连结条件的, 我们在上述查询的 ON 之后指定两张表连结所使用的列以及比较条件, 基本上, 它能起到与 WHERE 相同的筛选作用, 我们会在本章的结尾部分进一步探讨这个话题. 409 | 410 | **要点三: SELECT 子句中的列最好按照 表****名****.列名 的格式来使用.** 411 | 412 | 当两张表的列除了用于关联的列之外, 没有名称相同的列的时候, 也可以不写表名, 但表名使得我们能够在今后的任何时间阅读查询代码的时候, 都能马上看出每一列来自于哪张表, 能够节省我们很多时间. 413 | 414 | 但是, 如果两张表有其他名称相同的列, 则必须使用上述格式来选择列名, 否则查询语句会报错. 415 | 416 | 我们回到上述查询所回答的问题. 通过观察上述查询的结果, 我们发现, 这个结果离我们的目标: 找出东京商店的衣服类商品的基础信息已经很接近了. 接下来,我们只需要把这个查询结果作为一张表, 给它增加一个 WHERE 子句来指定筛选条件. 417 | 418 | ### 4.2.1.2 结合 WHERE 子句使用内连结 419 | 420 | 如果需要在使用内连结的时候同时使用 WHERE 子句对检索结果进行筛选, 则需要把 WHERE 子句写在 ON 子句的后边. 421 | 422 | 例如, 对于上述查询问题, 我们可以在前一步查询的基础上, 增加 WHERE 条件. 423 | 424 | 增加 WHERE 子句的方式有好几种,我们先从最简单的说起. 425 | 426 | 第一种增加 WEHRE 子句的方式, 就是把上述查询作为子查询, 用括号封装起来, 然后在外层查询增加筛选条件. 427 | 428 | ```sql 429 | SELECT * 430 |   FROM (-- 第一步查询的结果 431 |   SELECT SP.shop_id 432 | ,SP.shop_name 433 | ,SP.product_id 434 |   ,P.product_name 435 | ,P.product_type 436 | ,P.sale_price 437 | ,SP.quantity 438 |     FROM ShopProduct AS SP 439 |   INNER JOIN Product AS P 440 |   ON SP.product_id = P.product_id) AS STEP1 441 | WHERE shop_name = '东京' 442 | AND product_type = '衣服' ; 443 | ``` 444 | 还记得我们学习子查询时的认识吗? 子查询的结果其实也是一张表,只不过是一张虚拟的表, 它并不真实存在于数据库中, 只是数据库中其他表经过筛选,聚合等查询操作后得到的一个"视图". 445 | 这种写法能很清晰地分辨出每一个操作步骤, 在我们还不十分熟悉 SQL 查询每一个子句的执行顺序的时候可以帮到我们. 446 | 447 | 但实际上, 如果我们熟知 WHERE 子句将在 FROM 子句之后执行, 也就是说, 在做完 INNER JOIN ... ON 得到一个新表后, 才会执行 WHERE 子句, 那么就得到标准的写法: 448 | 449 | ```sql 450 | SELECT SP.shop_id 451 | ,SP.shop_name 452 | ,SP.product_id 453 |   ,P.product_name 454 | ,P.product_type 455 | ,P.sale_price 456 | ,SP.quantity 457 |   FROM ShopProduct AS SP 458 |  INNER JOIN Product AS P 459 |   ON SP.product_id = P.product_id 460 |  WHERE SP.shop_name = '东京' 461 |   AND P.product_type = '衣服' ; 462 | ``` 463 | 我们首先给出上述查询的执行顺序: 464 | 465 | FROM 子句->WHERE 子句->SELECT 子句 466 | 467 | 也就是说, 两张表是先按照连结列进行了连结, 得到了一张新表, 然后 WHERE 子句对这张新表的行按照两个条件进行了筛选, 最后, SELECT 子句选出了那些我们需要的列. 468 | 469 | 此外, 一种不是很常见的做法是,还可以将 WHERE 子句中的条件直接添加在 ON 子句中, 这时候 ON 子句后最好用括号将连结条件和筛选条件括起来. 470 | 471 | ```sql 472 | SELECT SP.shop_id 473 | ,SP.shop_name 474 | ,SP.product_id 475 |   ,P.product_name 476 | ,P.product_type 477 | ,P.sale_price 478 | ,SP.quantity 479 |   FROM ShopProduct AS SP 480 |  INNER JOIN Product AS P 481 |   ON (SP.product_id = P.product_id 482 |   AND SP.shop_name = '东京' 483 |   AND P.product_type = '衣服') ; 484 | ``` 485 | 但上述这种把筛选条件和连结条件都放在 ON 子句的写法, 不是太容易阅读, 不建议大家使用. 486 | 另外, 先连结再筛选的标准写法的执行顺序是, 两张完整的表做了连结之后再做筛选,如果要连结多张表, 或者需要做的筛选比较复杂时, 在写 SQL 查询时会感觉比较吃力. 在结合 WHERE 子句使用内连结的时候, 我们也可以更改任务顺序, 并采用任务分解的方法,先分别在两个表使用 WHERE 进行筛选,然后把上述两个子查询连结起来. 487 | 488 | ```sql 489 | SELECT SP.shop_id 490 | ,SP.shop_name 491 | ,SP.product_id 492 |   ,P.product_name 493 | ,P.product_type 494 | ,P.sale_price 495 | ,SP.quantity 496 |   FROM (-- 子查询 1:从 ShopProduct 表筛选出东京商店的信息 497 |   SELECT * 498 |   FROM ShopProduct 499 |   WHERE shop_name = '东京' ) AS SP 500 |  INNER JOIN -- 子查询 2:从 Product 表筛选出衣服类商品的信息 501 | (SELECT * 502 |   FROM Product 503 |   WHERE product_type = '衣服') AS P 504 |   ON SP.product_id = P.product_id; 505 | ``` 506 | 先分别在两张表里做筛选, 把复杂的筛选条件按表分拆, 然后把筛选结果(作为表)连接起来, 避免了写复杂的筛选条件, 因此这种看似复杂的写法, 实际上整体的逻辑反而非常清晰. 在写查询的过程中, 首先要按照最便于自己理解的方式来写, 先把问题解决了, 再思考优化的问题。 507 | 508 | **练习题:** 509 | 510 | 找出每个商店里的衣服类商品的名称及价格等信息. 希望得到如下结果: 511 | 512 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.18result2.png) 513 | 514 | ``` 515 | -- 参考答案 1--不使用子查询 516 | SELECT SP.shop_id,SP.shop_name,SP.product_id 517 |   ,P.product_name, P.product_type, P.purchase_price 518 |   FROM shopproduct  AS SP 519 | INNER JOIN Product AS P 520 | ON SP.product_id = P.product_id 521 |  WHERE P.product_type = '衣服'; 522 | ``` 523 | ``` 524 | -- 参考答案 2--使用子查询 525 | SELECT SP.shop_id, SP.shop_name, SP.product_id 526 |   ,P.product_name, P.product_type, P.purchase_price 527 |   FROM shopproduct AS SP 528 | INNER JOIN --从 Product 表找出衣服类商品的信息 529 | (SELECT product_id, product_name, product_type, purchase_price 530 |      FROM Product 531 |    WHERE product_type = '衣服')AS P 532 |   ON SP.product_id = P.product_id; 533 | ``` 534 | 上述第二种写法虽然包含了子查询, 并且代码行数更多, 但由于每一层的目的很明确, 更适于阅读, 并且在外连结的情形下, 还能避免错误使用 WHERE 子句导致外连结失效的问题, 相关示例见后文中的"结合 WHERE 子句使用外连结"章节。 535 | 536 | **练习题:** 537 | 538 | 分别使用连结两个子查询和不使用子查询的方式, 找出东京商店里, 售价低于 2000 的商品信息,希望得到如下结果. 539 | 540 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.19result3.png) 541 | 542 | ``` 543 | -- 参考答案 544 | -- 不使用子查询 545 | SELECT SP.*, P.* 546 |   FROM ShopProduct AS SP 547 |  INNER JOIN Product AS P 548 |   ON SP.product_id = P.product_id 549 |  WHERE shop_id = '000A' 550 |    AND sale_price < 2000; 551 | ``` 552 | ### 4.2.1.3 结合 GROUP BY 子句使用内连结 553 | 554 | 结合 GROUP BY 子句使用内连结, 需要根据分组列位于哪个表区别对待. 555 | 556 | 最简单的情形, 是在内连结之前就使用 GROUP BY 子句. 557 | 558 | 但是如果分组列和被聚合的列不在同一张表, 且二者都未被用于连结两张表, 则只能先连结, 再聚合. 559 | 560 | **练习题:** 561 | 562 | 每个商店中, 售价最高的商品的售价分别是多少? 563 | 564 | ```sql 565 | -- 参考答案 566 | SELECT SP.shop_id 567 | ,SP.shop_name 568 | ,MAX(P.sale_price) AS max_price 569 |   FROMshopproduct AS SP 570 |  INNER JOINproduct AS P 571 |     ON SP.product_id = P.product_id 572 |  GROUP BY SP.shop_id,SP.shop_name 573 | ``` 574 | **思考题:** 575 | 576 | 上述查询得到了每个商品售价最高的商品, 但并不知道售价最高的商品是哪一个.如何获取每个商店里售价最高的商品的名称和售价? 577 | >注: 这道题的一个简易的方式是使用下一章的窗口函数. 当然, 也可以使用其他我们已经学过的知识来实现, 例如, 在找出每个商店售价最高商品的价格后, 使用这个价格再与 Product 列进行连结, 但这种做法在价格不唯一时会出现问题. 578 | 579 | ### 4.2.1.4 自连结(SELF JOIN) 580 | 581 | 之前的内连结, 连结的都是不一样的两个表. 但实际上一张表也可以与自身作连结, 这种连接称之为自连结. 需要注意, 自连结并不是区分于内连结和外连结的第三种连结, 自连结可以是外连结也可以是内连结, 它是不同于内连结外连结的另一个连结的分类方法. 582 | 583 | ### 4.2.1.5 内连结与关联子查询 584 | 585 | 回忆第五章第三节关联子查询中的问题: 找出每个商品种类当中售价高于该类商品的平均售价的商品.当时我们是使用关联子查询来实现的. 586 | 587 | ```sql 588 | SELECT product_type, product_name, sale_price 589 |   FROM product AS P1 590 |  WHERE sale_price > (SELECT AVG(sale_price) 591 |                       FROM product AS P2 592 |                     WHERE P1.product_type = P2.product_type 593 |                     GROUP BY product_type); 594 | ``` 595 | 使用内连结同样可以解决这个问题: 596 | 首先, 使用 GROUP BY 按商品类别分类计算每类商品的平均价格. 597 | 598 | ```sql 599 | SELECT product_type 600 | ,AVG(sale_price) AS avg_price 601 | FROM Product 602 | GROUP BY product_type; 603 | ``` 604 | 接下来, 将上述查询与表 Product 按照 product_type (商品种类)进行内连结. 605 | ``` 606 | SELECT  P1.product_id 607 | ,P1.product_name 608 |   ,P1.product_type 609 | ,P1.sale_price 610 |   ,P2.avg_price 611 | FROM Product AS P1 612 | INNER JOIN 613 | (SELECT product_type,AVG(sale_price) AS avg_price 614 | FROM Product 615 | GROUP BY product_type) AS P2 616 |   ON P1.product_type = P2.product_type; 617 | ``` 618 | 最后, 增加 WHERE 子句, 找出那些售价高于该类商品平均价格的商品.完整的代码如下: 619 | ```sql 620 | SELECT  P1.product_id 621 | ,P1.product_name 622 | ,P1.product_type 623 |   ,P1.sale_price 624 | ,P2.avg_price 625 | FROM Product AS P1 626 | INNER JOIN 627 | (SELECT product_type,AVG(sale_price) AS avg_price 628 |  FROM Product 629 | GROUP BY product_type) AS P2 630 |     ON P1.product_type = P2.product_type 631 | WHERE P1.sale_price > P2.avg_price; 632 | ``` 633 | 仅仅从代码量上来看, 上述方法似乎比关联子查询更加复杂, 但这并不意味着这些代码更难理解. 通过上述分析, 很容易发现上述代码的逻辑实际上更符合我们的思路, 因此尽管看起来复杂, 但思路实际上更加清晰。 634 | 635 | ### 4.2.1.6 自然连结(NATURAL JOIN) 636 | 637 | 自然连结并不是区别于内连结和外连结的第三种连结, 它其实是内连结的一种特例--当两个表进行自然连结时, 会按照两个表中都包含的列名来进行等值内连结, 此时无需使用 ON 来指定连接条件. 638 | 639 | ```sql 640 | SELECT * FROM shopproduct NATURAL JOIN Product 641 | ``` 642 | 上述查询得到的结果, 会把两个表的公共列(这里是 product_id, 可以有多个公共列)放在第一列, 然后按照两个表的顺序和表中列的顺序, 将两个表中的其他列都罗列出来. 643 | 644 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.20.png) 645 | 646 | **练习题:** 647 | 648 | 试写出与上述自然连结等价的内连结. 649 | 650 | ```sql 651 | -- 参考答案 652 | SELECT SP.product_id,SP.shop_id,SP.shop_name,SP.quantity 653 |   ,P.product_name,P.product_type,P.sale_price 654 |   ,P.purchase_price,P.regist_date   655 |   FROM shopproduct AS SP 656 |  INNER JOIN Product AS P 657 |   ON SP.product_id = P.product_id 658 | ``` 659 | 使用自然连结还可以求出两张表或子查询的公共部分, 例如教材中 7-1 选取表中公共部分--INTERSECT 一节中的问题: 求表 Product 和表 Product2 中的公共部分, 也可以用自然连结来实现: 660 | 661 | ```sql 662 | SELECT * FROM Product NATURAL JOIN Product2 663 | ``` 664 | 665 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.21.png) 666 | 667 | 这个结果和书上给的结果并不一致, 少了运动 T 恤, 这是由于运动 T 恤的 regist_date 字段为空, 在进行自然连结时, 来自于 Product 和 Product2 的运动 T 恤这一行数据在进行比较时, 实际上是在逐字段进行等值连结, 回忆我们在 6.2ISNULL,IS NOT NULL 这一节学到的缺失值的比较方法就可得知, 两个缺失值用等号进行比较, 结果不为真. 而连结只会返回对连结条件返回为真的那些行. 668 | 669 | 如果我们将查询语句进行修改: 670 | 671 | ```sql 672 | SELECT * 673 |   FROM (SELECT product_id, product_name 674 |           FROM Product ) AS A  675 | NATURAL JOIN  676 | (SELECT product_id, product_name 677 |   FROM Product2) AS B; 678 | ``` 679 | 那就可以得到正确的结果了: 680 | 681 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.22.png) 682 | 683 | ### 4.2.1.7 使用连结求交集 684 | 685 | 我们在上一节表的加减法里知道, MySQL 8.0 里没有交集运算, 我们当时是通过并集和差集来实现求交集的. 现在学了连结, 让我们试试使用连结来实现求交集的运算. 686 | 687 | 练习题: 使用内连结求 Product 表和 Product2 表的交集. 688 | 689 | ```sql 690 | SELECT P1.* 691 | FROM Product AS P1 692 |  INNER JOIN Product2 AS P2 693 |   ON (P1.product_id = P2.product_id 694 |   AND P1.product_name = P2.product_name 695 |   AND P1.product_type = P2.product_type 696 |   AND P1.sale_price = P2.sale_price 697 |   AND P1.regist_date = P2.regist_date) 698 | ``` 699 | 得到如下结果 700 | 701 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.23.png) 702 | 703 | 注意上述结果和 P230 的结果并不一致--少了 product_id='0001'这一行, 观察源表数据可发现, 少的这行数据的 regist_date 为缺失值, 回忆第六章讲到的 IS NULL 谓词, 我们得知, 这是由于缺失值是不能用等号进行比较导致的. 704 | 705 | 如果我们仅仅用 product_id 来进行连结: 706 | 707 | ```sql 708 | SELECT P1.* 709 | FROM Product AS P1 710 |  INNER JOIN Product2 AS P2 711 |   ON P1.product_id = P2.product_id 712 | ``` 713 | 查询结果: 714 | 715 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.24.png) 716 | 717 | 这次就一致了. 718 | 719 | ## 4.2.2 外连结(OUTER JOIN) 720 | 721 | 内连结会丢弃两张表中不满足 ON 条件的行,和内连结相对的就是外连结. 外连结会根据外连结的种类有选择地保留无法匹配到的行. 722 | 723 | 按照保留的行位于哪张表,外连结有三种形式: 左连结, 右连结和全外连结. 724 | 725 | 左连结会保存左表中无法按照 ON 子句匹配到的行, 此时对应右表的行均为缺失值; 右连结则会保存右表中无法按照 ON 子句匹配到的行, 此时对应左表的行均为缺失值; 而全外连结则会同时保存两个表中无法按照 ON子句匹配到的行, 相应的另一张表中的行用缺失值填充. 726 | 727 | 三种外连结的对应语法分别为: 728 | 729 | ```sql 730 | -- 左连结 731 | FROM LEFT OUTER JOIN ON 732 | -- 右连结 733 | FROM RIGHT OUTER JOIN ON 734 | -- 全外连结 735 | FROM FULL OUTER JOIN ON 736 | ``` 737 | ### 738 | ### 4.2.2.1 左连结与右链接 739 | 740 | 由于连结时可以交换左表和右表的位置, 因此左连结和右连结并没有本质区别.接下来我们先以左连结为例进行学习. 所有的内容在调换两个表的前后位置, 并将左连结改为右连结之后, 都能得到相同的结果. 稍后再介绍全外连结的概念. 741 | 742 | ### 4.2.2.2 使用左连结从两个表获取信息 743 | 744 | 如果你仔细观察过将 ShopProduct 和 Product 进行内连结前后的结果的话, 你就会发现, Product 表中有两种商品并未在内连结的结果里, 就是说, 这两种商品并未在任何商店有售(这通常意味着比较重要的业务信息, 例如, 这两种商品在所有商店都处于缺货状态, 需要及时补货). 现在, 让我们先把之前内连结的 SELECT 语句转换为左连结试试看吧. 745 | 746 | 练习题: 统计每种商品分别在哪些商店有售, 需要包括那些在每个商店都没货的商品. 747 | 748 | 使用左连结的代码如下(注意区别于书上的右连结): 749 | 750 | ```sql 751 | SELECT SP.shop_id 752 | ,SP.shop_name 753 | ,SP.product_id 754 |   ,P.product_name 755 | ,P.sale_price 756 |   FROM Product AS P 757 |   LEFT OUTER JOIN ShopProduct AS SP 758 |   ON SP.product_id = P.product_id; 759 | ``` 760 | 上述查询得到的检索结果如下(由于并未使用 ORDER BY 子句指定顺序,你执行上述代码得到的结果可能顺序与下图不同): 761 | 762 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.25.png) 763 | 764 | 我们观察上述结果可以发现, 有两种商品: 高压锅和圆珠笔, 在所有商店都没有销售. 由于我们在 SELECT 子句选择列的显示顺序以及未对结果进行排序的原因, 这个事实需要你仔细地进行观察. 765 | 766 | **●外连结要点 1: 选取出单张表中全部的信息** 767 | 768 | 与内连结的结果相比,不同点显而易见,那就是结果的行数不一样.内连结的结果中有 13 条记录,而外连结的结果中有 15 条记录,增加的 2 条记录到底是什么呢?这正是外连结的关键点. 多出的 2 条记录是高压锅和圆珠笔,这 2 条记录在 ShopProduct 表中并不存在,也就是说,这 2 种商品在任何商店中都没有销售.由于内连结只能选取出同时存在于两张表中的数据,因此只在 Product 表中存在的 2 种商品并没有出现在结果之中.相反,对于外连结来说,只要数据存在于某一张表当中,就能够读取出来.在实际的业务中,例如想要生成固定行数的单据时,就需要使用外连结.如果使用内连结的话,根据 SELECT 语句执行时商店库存状况的不同,结果的行数也会发生改变,生成的单据的版式也会受到影响,而使用外连结能够得到固定行数的结果.虽说如此,那些表中不存在的信息我们还是无法得到,结果中高压锅和圆珠笔的商店编号和商店名称都是 NULL (具体信息大家都不知道,真是无可奈何).外连结名称的由来也跟 NULL 有关,即“结果中包含原表中不存在(在原表之外)的信息”.相反,只包含表内信息的连结也就被称为内连结了. 769 | 770 | **●********外连结要点 2:使用 LEFT、RIGHT 来指定主表.** 771 | 772 | 外连结还有一点非常重要,那就是要把哪张表作为主表.最终的结果中会包含主表内所有的数据.指定主表的关键字是 LEFT 和 RIGHT.顾名思义,使用 LEFT 时 FROM 子句中写在左侧的表是主表,使用 RIGHT 时右侧的表是主表.代码清单 7-11 中使用了 RIGHT ,因此,右侧的表,也就是 Product 表是主表.我们还可以像代码清单 7-12 这样进行改写,意思完全相同.这样你可能会困惑,到底应该使用 LEFT 还是 RIGHT?其实它们的功能没有任何区别,使用哪一个都可以.通常使用 LEFT 的情况会多一些,但也并没有非使用这个不可的理由,使用 RIGHT 也没有问题. 773 | 774 | 通过交换两个表的顺序, 同时将 LEFT 更换为 RIGHT(如果原先是 RIGHT,则更换为 LEFT), 两种方式会到完全相同的结果. 775 | 776 | 777 | 778 | ### 4.2.2.3 结合 WHERE 子句使用左连结 779 | 780 | 上一小节我们学到了外连结的基础用法, 并且在上一节也学习了结合WHERE子句使用内连结的方法, 但在结合WHERE子句使用外连结时, 由于外连结的结果很可能与内连结的结果不一样, 会包含那些主表中无法匹配到的行, 并用缺失值填写另一表中的列, 由于这些行的存在, 因此在外连结时使用WHERE子句, 情况会有些不一样. 我们来看一个例子: 781 | 782 | **练习题:** 783 | 784 | 使用外连结从ShopProduct表和Product表中找出那些在某个商店库存少于50的商品及对应的商店.希望得到如下结果. 785 | 786 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.26.png) 787 | 788 | 注意高压锅和圆珠笔两种商品在所有商店都无货, 所以也应该包括在内. 789 | 790 | 按照"结合WHERE子句使用内连结"的思路, 我们很自然会写出如下代码 791 | 792 | ```sql 793 | SELECT P.product_id 794 | ,P.product_name 795 | ,P.sale_price 796 |   ,SP.shop_id 797 | ,SP.shop_name 798 | ,SP.quantity 799 |   FROM Product AS P 800 |   LEFT OUTER JOIN ShopProduct AS SP 801 |   ON SP.product_id = P.product_id 802 |  WHERE quantity< 50 803 | ``` 804 | 然而不幸的是, 得到的却是如下的结果: 805 | 806 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.27.png) 807 | 808 | 观察发现, 少了在所有商店都无货的高压锅和圆珠笔. 聪明的你可能很容易想到,在WHERE过滤条件中增加 **`OR quantity IS NULL`** 的条件, 便可以得到预期的结果。然而在真实的查询环境中, 由于数据量大且数据质量并非设想的那样"干净", 我们并不能容易地意识到缺失值等问题数据的存在, 因此,还是让我们想一下如何改写我们的查询以使得它能够适应更复杂的真实数据的情形吧。 809 | 810 | 联系到我们已经掌握了的SQL查询的执行顺序(FROM->WHERE->SELECT),我们发现, 问题可能出在筛选条件上, 因为在进行完外连结后才会执行WHERE子句, 因此那些主表中无法被匹配到的行就被WHERE条件筛选掉了. 811 | 812 | 明白了这一点, 我们就可以试着把WHERE子句挪到外连结之前进行: 先写个子查询,用来从ShopProduct表中筛选quantity<50的商品, 然后再把这个子查询和主表连结起来. 813 | 814 | 我们把上述思路写成SQL查询语句: 815 | 816 | ```sql 817 | SELECT P.product_id 818 | ,P.product_name 819 | ,P.sale_price 820 | ,SP.shop_id 821 | ,SP.shop_name 822 | ,SP.quantity 823 |   FROM Product AS P 824 |   LEFT OUTER JOIN-- 先筛选quantity<50的商品 825 | (SELECT * 826 |   FROM ShopProduct 827 |   WHERE quantity < 50 ) AS SP 828 |   ON SP.product_id = P.product_id 829 | ``` 830 | 得到的结果如下: 831 | 832 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.28.png) 833 | 834 | 835 | 836 | ### 4.2.2.4 在 MySQL 中实现全外连结 837 | 838 | 有了对左连结和右连结的了解, 就不难理解全外连结的含义了. 全外连结本质上就是对左表和右表的所有行都予以保留, 能用 ON 关联到的就把左表和右表的内容在一行内显示, 不能被关联到的就分别显示, 然后把多余的列用缺失值填充. 839 | 840 | 遗憾的是, MySQL8.0 目前还不支持全外连结, 不过我们可以对左连结和右连结的结果进行 UNION 来实现全外连结. 841 | 842 | ## 4.2.3 多表连结 843 | 844 | 通常连结只涉及 2 张表,但有时也会出现必须同时连结 3 张以上的表的情况, 原则上连结表的数量并没有限制. 845 | 846 | ### 4.2.3.1 多表进行内连结 847 | 848 | 首先创建一个用于三表连结的表 InventoryProduct.首先我们创建一张用来管理库存商品的表, 假设商品都保存在 P001 和 P002 这 2 个仓库之中. 849 | 850 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.29.png) 851 | 852 | 建表语句如下: 853 | 854 | ``` 855 | CREATE TABLE InventoryProduct 856 | ( inventory_id CHAR(4) NOT NULL, 857 | product_id CHAR(4) NOT NULL, 858 | inventory_quantity INTEGER NOT NULL, 859 | PRIMARY KEY (inventory_id, product_id)); 860 | ``` 861 | 然后插入一些数据: 862 | ``` 863 | --- DML:插入数据 864 | START TRANSACTION; 865 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 866 | VALUES ('P001', '0001', 0); 867 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 868 | VALUES ('P001', '0002', 120); 869 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 870 | VALUES ('P001', '0003', 200); 871 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 872 | VALUES ('P001', '0004', 3); 873 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 874 | VALUES ('P001', '0005', 0); 875 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 876 | VALUES ('P001', '0006', 99); 877 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 878 | VALUES ('P001', '0007', 999); 879 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 880 | VALUES ('P001', '0008', 200); 881 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 882 | VALUES ('P002', '0001', 10); 883 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 884 | VALUES ('P002', '0002', 25); 885 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 886 | VALUES ('P002', '0003', 34); 887 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 888 | VALUES ('P002', '0004', 19); 889 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 890 | VALUES ('P002', '0005', 99); 891 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 892 | VALUES ('P002', '0006', 0); 893 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 894 | VALUES ('P002', '0007', 0 ); 895 | INSERT INTO InventoryProduct (inventory_id, product_id, inventory_quantity) 896 | VALUES ('P002', '0008', 18); 897 | COMMIT; 898 | ``` 899 | 接下来, 我们根据上表及 ShopProduct 表和 Product 表, 使用内连接找出每个商店都有那些商品, 每种商品的库存总量分别是多少. 900 | ``` 901 | SELECT SP.shop_id 902 | ,SP.shop_name 903 | ,SP.product_id 904 |   ,P.product_name 905 | ,P.sale_price 906 | ,IP.inventory_quantity 907 |   FROM ShopProduct AS SP 908 |  INNER JOIN Product AS P 909 |   ON SP.product_id = P.product_id 910 | INNER JOIN InventoryProduct AS IP 911 |   ON SP.product_id = IP.product_id 912 |  WHERE IP.inventory_id = 'P001'; 913 | ``` 914 | 得到如下结果 915 | 916 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.30.png) 917 | 918 | 我们可以看到, 连结第三张表的时候, 也是通过 ON 子句指定连结条件(这里使用最基础的等号将作为连结条件的 Product 表和 ShopProduct 表中的商品编号 product _id 连结了起来), 由于 Product 表和 ShopProduct 表已经进行了连结,因此就无需再对 Product 表和 InventoryProduct 表进行连结了(虽然也可以进行连结,但结果并不会发生改变, 因为本质上并没有增加新的限制条件). 919 | 920 | 即使想要把连结的表增加到 4 张、5 张……使用 INNER JOIN 进行添加的方式也是完全相同的. 921 | 922 | ### 4.2.3.2 多表进行外连结 923 | 924 | 正如之前所学发现的, 外连结一般能比内连结有更多的行, 从而能够比内连结给出更多关于主表的信息, 多表连结的时候使用外连结也有同样的作用. 925 | 926 | 例如, 927 | 928 | ```sql 929 | SELECT P.product_id 930 | ,P.product_name 931 | ,P.sale_price 932 |   ,SP.shop_id 933 | ,SP.shop_name 934 | ,IP.inventory_quantity 935 |   FROM Product AS P 936 | LEFT OUTER JOIN ShopProduct AS SP 937 | ON SP.product_id = P.product_id 938 | LEFT OUTER JOIN InventoryProduct AS IP 939 | ON SP.product_id = IP.product_id 940 | ``` 941 | 查询结果 942 | 943 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.31.png) 944 | 945 | ## 4.2.4 ON 子句进阶--非等值连结 946 | 947 | 在刚开始介绍连结的时候, 书上提到过, 除了使用相等判断的等值连结, 也可以使用比较运算符来进行连接. 实际上, 包括比较运算符(<,<=,>,>=, BETWEEN)和谓词运算(LIKE, IN, NOT 等等)在内的所有的逻辑运算都可以放在 ON 子句内作为连结条件. 948 | 949 | ### 4.2.4.1 非等值自左连结(SELF JOIN) 950 | 951 | 使用非等值自左连结实现排名。 952 | 953 | **练习题:** 954 | 955 | 希望对 Product 表中的商品按照售价赋予排名. 一个从集合论出发,使用自左连结的思路是, 对每一种商品,找出售价不低于它的所有商品, 然后对售价不低于它的商品使用 COUNT 函数计数. 例如, 对于价格最高的商品, 956 | 957 | ```sql 958 | SELECT product_id 959 | ,product_name 960 | ,sale_price 961 | ,COUNT(p2_id) AS my_rank 962 | FROM (--使用自左连结对每种商品找出价格不低于它的商品 963 |   SELECT P1.product_id 964 |   ,P1.product_name 965 |   ,P1.sale_price 966 |   ,P2.product_id AS P2_id 967 |   ,P2.product_name AS P2_name 968 |   ,P2.sale_price AS P2_price  969 |   FROM Product AS P1 970 |    LEFT OUTER JOIN Product AS P2  971 |  ON P1.sale_price <= P2.sale_price  972 | ) AS X 973 | GROUP BY product_id, product_name, sale_price 974 | ORDER BY my_rank;  975 | ``` 976 | 注 1: COUNT 函数的参数是列名时, 会忽略该列中的缺失值, 参数为 * 时则不忽略缺失值. 977 | 注 2: 上述排名方案存在一些问题--如果两个商品的价格相等, 则会导致两个商品的排名错误, 例如, 叉子和打孔器的排名应该都是第六, 但上述查询导致二者排名都是第七. 试修改上述查询使得二者的排名均为第六. 978 | 979 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.32.png) 980 | 981 | 注 3: 实际上, 进行排名有专门的函数, 这是 MySQL 8.0 新增加的窗口函数中的一种(窗口函数将在下一章学习), 但在较低版本的 MySQL 中只能使用上述自左连结的思路. 982 | 983 | 使用非等值自左连结进行累计求和: 984 | 985 | **练习题:** 986 | 987 | 请按照商品的售价从低到高,对售价进行累计求和[注:这个案例缺少实际意义, 并且由于有两种商品价格相同导致了不必要的复杂度, 但示例数据库的表结构比较简单, 暂时未想出有实际意义的例题] 988 | 989 | 首先, 按照题意, 对每种商品使用自左连结, 找出比该商品售价价格更低或相等的商品 990 | 991 | ```sql 992 | SELECT P1.product_id 993 | ,P1.product_name 994 | ,P1.sale_price 995 |   ,P2.product_id AS P2_id 996 | ,P2.product_name AS P2_name 997 |   ,P2.sale_price AS P2_price 998 | FROM Product AS P1 999 | LEFT OUTER JOIN Product AS P2 1000 | ON P1.sale_price >= P2.sale_price 1001 | ORDER BY P1.sale_price,P1.product_id 1002 | ``` 1003 | 查看查询结果 1004 | 1005 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.33.png) 1006 | 1007 | 看起来似乎没什么问题. 1008 | 1009 | 下一步, 按照 P1.product_Id 分组,对 P2_price 求和: 1010 | 1011 | ```sql 1012 | SELECT product_id 1013 | ,product_name 1014 |   ,sale_price 1015 | ,SUM(P2_price) AS cum_price 1016 | FROM (SELECT  P1.product_id 1017 | ,P1.product_name 1018 | ,P1.sale_price 1019 | ,P2.product_id AS P2_id 1020 | ,P2.product_name AS P2_name 1021 | ,P2.sale_price AS P2_price  1022 |   FROM Product AS P1 1023 | LEFT OUTER JOIN Product AS P2 1024 | ON P1.sale_price >= P2.sale_price 1025 | ORDER BY P1.sale_price,P1.product_id ) AS X 1026 | GROUP BY product_id, product_name, sale_price 1027 | ORDER BY sale_price,product_id; 1028 | ``` 1029 | 得到的查询结果为: 1030 | 1031 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.34.png) 1032 | 1033 | 观察上述查询结果发现, 由于有两种商品的售价相同, 在使用 >= 进行连结时, 导致了累计求和错误, 这是由于这两种商品售价相同导致的. 因此实际上之前是不应该单独只用 >= 作为连结条件的. 考察我们建立自左连结的本意, 是要找出满足:1.比该商品售价更低的, 或者是 2.该种商品自身,以及 3.如果 A 和 B 两种商品售价相等,则建立连结时, 如果 P1.A 和 P2.A,P2.B 建立了连接, 则 P1.B 不再和 P2.A 建立连结, 因此根据上述约束条件, 利用 ID 的有序性, 进一步将上述查询改写为: 1034 | 1035 | ```sql 1036 | SELECT product_id, product_name, sale_price 1037 |   ,SUM(P2_price) AS cum_price  1038 |   FROM 1039 |   (SELECT P1.product_id, P1.product_name, P1.sale_price 1040 |         ,P2.product_id AS P2_id 1041 |   ,P2.product_name AS P2_name 1042 |   ,P2.sale_price AS P2_price  1043 |     FROM Product AS P1 1044 |   LEFT OUTER JOIN Product AS P2 1045 |   ON ((P1.sale_price > P2.sale_price) 1046 |              OR (P1.sale_price = P2.sale_price 1047 |   AND P1.product_id<=P2.product_id)) 1048 | ORDER BY P1.sale_price,P1.product_id) AS X 1049 |  GROUP BY product_id, product_name, sale_price 1050 |  ORDER BY sale_price,cum_price; 1051 | ``` 1052 | 这次结果就正确了. 1053 | 1054 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.35.png) 1055 | 1056 | ## 4.2.5 交叉连结—— CROSS JOIN(笛卡尔积) 1057 | 1058 | 之前的无论是外连结内连结, 一个共同的必备条件就是连结条件--ON 子句, 用来指定连结的条件. 如果你试过不使用这个连结条件的连结查询, 你可能已经发现, 结果会有很多行. 在连结去掉 ON 子句, 就是所谓的交叉连结(CROSS JOIN), 交叉连结又叫笛卡尔积, 后者是一个数学术语. 两个集合做笛卡尔积, 就是使用集合 A 中的每一个元素与集合 B 中的每一个元素组成一个有序的组合. 数据库表(或者子查询)的并,交和差都是在纵向上对表进行扩张或筛选限制等运算的, 这要求表的列数及对应位置的列的数据类型"相容", 因此这些运算并不会增加新的列, 而交叉连接(笛卡尔积)则是在横向上对表进行扩张, 即增加新的列, 这一点和连结的功能是一致的. 但因为没有了ON子句的限制, 会对左表和右表的每一行进行组合, 这经常会导致很多无意义的行出现在检索结果中. 当然, 在某些查询需求中, 交叉连结也有一些用处. 1059 | 1060 | 交叉连结的语法有如下几种形式: 1061 | 1062 | ```sql 1063 | -- 1.使用关键字 CROSS JOIN 显式地进行交叉连结 1064 | SELECT SP.shop_id 1065 | ,SP.shop_name 1066 | ,SP.product_id 1067 |   ,P.product_name 1068 | ,P.sale_price 1069 | FROM ShopProduct AS SP 1070 |  CROSS JOIN Product AS P; 1071 | --2.使用逗号分隔两个表,并省略 ON 子句 1072 | SELECT SP.shop_id 1073 | ,SP.shop_name 1074 | ,SP.product_id 1075 | ,P.product_name 1076 | ,P.sale_price 1077 |   FROM ShopProduct AS SP , Product AS P; 1078 | ``` 1079 | 请大家试着执行一下以上语句. 1080 | 可能大家会惊讶于结果的行数, 但我们还是先来介绍一下语法结构吧.对满足相同规则的表进行交叉连结的集合运算符是 CROSS JOIN (笛卡儿积).进行交叉连结时无法使用内连结和外连结中所使用的ON 子句,这是因为交叉连结是对两张表中的全部记录进行交叉组合,因此结果中的记录数通常是两张表中行数的乘积.本例中,因为 ShopProduct 表存在 13 条记录,Product 表存在 8 条记录,所以结果中就包含了 13 × 8 = 104 条记录. 1081 | 1082 | 可能这时会有读者想起前面我们提到过集合运算中的乘法会在本节中进行详细学习,这就是上面介绍的交叉连结.内连结是交叉连结的一部分,“内”也可以理解为“包含在交叉连结结果中的部分”.相反,外连结的“外”可以理解为“交叉连结结果之外的部分”. 1083 | 1084 | 交叉连结没有应用到实际业务之中的原因有两个.一是其结果没有实用价值,二是由于其结果行数太多,需要花费大量的运算时间和高性能设备的支持. 1085 | 1086 | ### 4.2.5.1 [扩展阅读]连结与笛卡儿积的关系 1087 | 1088 | 考察笛卡儿积和连结, 不难发现, 笛卡儿积可以视作一种特殊的连结(事实上笛卡儿积的语法也可以写作 CROSS JOIN), 这种连结的 ON 子句是一个恒为真的谓词. 1089 | 1090 | 反过来思考, 在对笛卡儿积进行适当的限制之后, 也就得到了内连结和外连结. 1091 | 1092 | 例如, 对于 ShopProduct 表和 Product 表, 首先建立笛卡尔乘积: 1093 | 1094 | ``` 1095 | SELECT SP.*, P.* 1096 | FROM ShopProduct AS SP 1097 | CROSS JOIN Product AS P; 1098 | ``` 1099 | 查询结果的一部分如下: 1100 | 1101 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.36.png) 1102 | 1103 | 然后对上述笛卡尔乘积增加筛选条件 SP.product_id=P.product_id, 就得到了和内连结一致的结果: 1104 | 1105 | ``` 1106 | SELECT SP.*, P.* 1107 | FROM ShopProduct AS SP 1108 | CROSS JOIN Product AS P 1109 | WHERE SP.product_id = P.product_id; 1110 | ``` 1111 | 查询结果如下: 1112 | 1113 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch04/ch04.37.png) 1114 | 1115 | 实际上, 正如书中所说, 上述写法中, 将 CROSS JOIN 改为逗号后, 正是内连结的旧式写法, 但在 ANSI 和 ISO 的 SQL-92 标准中, 已经将使用 INNER JION ..ON.. 的写法规定为标准写法, 因此极力推荐大家在平时写 SQL 查询时, 使用规范写法. 1116 | 1117 | 1118 | ## 4.2.6 连结的特定语法和过时语法 1119 | 1120 | 在笛卡尔积的基础上, 我们增加一个 WHERE 子句, 将之前的连结条件作为筛选条件加进去, 我们会发现, 得到的结果恰好是直接使用内连接的结果. 1121 | 1122 | 试执行以下查询, 并将查询结果与内连结一节第一个例子的结果做对比. 1123 | 1124 | ```sql 1125 | SELECT SP.shop_id 1126 | ,SP.shop_name 1127 | ,SP.product_id 1128 | ,P.product_name 1129 | ,P.sale_price 1130 |   FROM ShopProduct AS SP 1131 |  CROSS JOIN Product AS P 1132 |  WHERE SP.product_id = P.product_id; 1133 | ``` 1134 | 我们发现, 这两个语句得到的结果是相同的. 1135 | 之前我们学习的内连结和外连结的语法都符合标准 SQL 的规定,可以在所有 DBMS 中执行,因此大家可以放心使用. 但是如果大家之后从事系统开发工作, 或者阅读遗留SQL 查询语句的话,一定会碰到需要阅读他人写的代码并进行维护的情况,而那些使用特定和过时语法的程序就会成为我们的麻烦. 1136 | 1137 | SQL 是一门特定语法及过时语法非常多的语言,虽然之前本书中也多次提及,但连结是其中特定语法的部分,现在还有不少年长的程序员和系统工程师仍在使用这些特定的语法.例如,将本节最初介绍的内连结的 SELECT 语句替换为过时语法的结果如下所示. 1138 | 1139 | 使用过时语法的内连结(结果与代码清单 7-9 相同) 1140 | 1141 | ```sql 1142 | SELECT SP.shop_id 1143 | ,SP.shop_name 1144 | ,SP.product_id 1145 | ,P.product_name 1146 | ,P.sale_price 1147 | FROM ShopProduct SP, Product P 1148 | WHERE SP.product_id = P.product_id 1149 | AND SP.shop_id = '000A'; 1150 | ``` 1151 | 这样的书写方式所得到的结果与标准语法完全相同,并且这样的语法可以在所有的 DBMS 中执行,并不能算是特定的语法,只是过时了而已. 1152 | 但是,由于这样的语法不仅过时,而且还存在很多其他的问题,因此不推荐大家使用,理由主要有以下三点: 1153 | 1154 | 第一,使用这样的语法无法马上判断出到底是内连结还是外连结(又或者是其他种类的连结). 1155 | 1156 | 第二,由于连结条件都写在 WHERE 子句之中,因此无法在短时间内分辨出哪部分是连结条件,哪部分是用来选取记录的限制条件. 1157 | 1158 | 第三,我们不知道这样的语法到底还能使用多久.每个 DBMS 的开发者都会考虑放弃过时的语法,转而支持新的语法.虽然并不是马上就不能使用了,但那一天总会到来的. 1159 | 1160 | 虽然这么说,但是现在使用这些过时语法编写的程序还有很多,到目前为止还都能正常执行.我想大家很可能会碰到这样的代码,因此还是希望大家能够了解这些知识. 1161 | 1162 | # 练习题 1163 | # **4.1** 1164 | 1165 | 找出 product 和 product2 中售价高于 500 的商品的基本信息。 1166 | 1167 | # **4.2** 1168 | 1169 | 借助对称差的实现方式, 求product和product2的交集。 1170 | 1171 | # **4.3** 1172 | 1173 | 每类商品中售价最高的商品都在哪些商店有售 ? 1174 | 1175 | # **4.4** 1176 | 1177 | 分别使用内连结和关联子查询每一类商品中售价最高的商品。 1178 | 1179 | # **4.5** 1180 | 1181 | 用关联子查询实现:在 product 表中,取出 product_id, produc_name, slae_price, 并按照商品的售价从低到高进行排序、对售价进行累计求和。 1182 | 1183 | 1184 | 1185 | 1186 | -------------------------------------------------------------------------------- /Task05:SQL高级处理.md: -------------------------------------------------------------------------------- 1 | # 5.1 窗口函数 2 | 3 | ## 5.1.1 窗口函数概念及基本的使用方法 4 | 5 | 窗口函数也称为**OLA****P****函数**。OLAP 是OnLine AnalyticalProcessing 的简称,意思是对数据库数据进行实时分析处理。 6 | 7 | 为了便于理解,称之为窗口函数。常规的SELECT语句都是对整张表进行查询,而窗口函数可以让我们有选择的去某一部分数据进行汇总、计算和排序。 8 | 9 | 窗口函数的通用形式: 10 | 11 | ```sql 12 | <窗口函数> OVER ([PARTITION BY <列名>] 13 | ORDER BY <排序用列名>)   14 | ``` 15 | *[]中的内容可以省略。 16 | 窗口函数最关键的是搞明白关键字**PARTITON BY**和**ORDER BY**的作用。 17 | 18 | **PARTITON BY**是用来分组,即选择要看哪个窗口,类似于GROUP BY 子句的分组功能,但是PARTITION BY 子句并不具备GROUP BY 子句的汇总功能,并不会改变原始表中记录的行数。 19 | 20 | **ORDER BY**是用来排序,即决定窗口内,是按那种规则(字段)来排序的。 21 | 22 | 举个栗子: 23 | 24 | ```sql 25 | SELECT product_name 26 | ,product_type 27 | ,sale_price 28 | ,RANK() OVER (PARTITION BY product_type 29 | ORDER BY sale_price) AS ranking 30 | FROM product   31 | ``` 32 | 33 | 得到的结果是: 34 | 35 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0501.png) 36 | 37 | 我们先忽略生成的新列 - [ranking], 看下原始数据在PARTITION BY 和 ORDER BY 关键字的作用下发生了什么变化。 38 | 39 | PARTITION BY 能够设定窗口对象范围。本例中,为了按照商品种类进行排序,我们指定了product_type。即一个商品种类就是一个小的"窗口"。 40 | 41 | ORDER BY 能够指定按照哪一列、何种顺序进行排序。为了按照销售单价的升序进行排列,我们指定了sale_price。此外,窗口函数中的ORDER BY与SELECT语句末尾的ORDER BY一样,可以通过关键字ASC/DESC来指定升序/降序。省略该关键字时会默认按照ASC,也就是 42 | 43 | 升序进行排序。本例中就省略了上述关键字 。 44 | 45 | 46 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0502.png) 47 | 48 | 49 | 50 | # 5.2 窗口函数种类 51 | 52 | 大致来说,窗口函数可以分为两类。 53 | 54 | 一是 将SUM、MAX、MIN等聚合函数用在窗口函数中 55 | 56 | 二是 RANK、DENSE_RANK等排序用的专用窗口函数 57 | 58 | ## 5.2.1 专用窗口函数 59 | 60 | * **RANK函数** 61 | 62 | 计算排序时,如果存在相同位次的记录,则会跳过之后的位次。 63 | 64 | 例)有 3 条记录排在第 1 位时:1 位、1 位、1 位、4 位…… 65 | 66 | * **DENSE_RANK函数** 67 | 68 | 同样是计算排序,即使存在相同位次的记录,也不会跳过之后的位次。 69 | 70 | 例)有 3 条记录排在第 1 位时:1 位、1 位、1 位、2 位…… 71 | 72 | * **ROW_NUMBER函数** 73 | 74 | 赋予唯一的连续位次。 75 | 76 | 例)有 3 条记录排在第 1 位时:1 位、2 位、3 位、4 位 77 | 78 | 运行以下代码: 79 | 80 | ```sql 81 | SELECT product_name 82 | ,product_type 83 | ,sale_price 84 | ,RANK() OVER (ORDER BY sale_price) AS ranking 85 | ,DENSE_RANK() OVER (ORDER BY sale_price) AS dense_ranking 86 | ,ROW_NUMBER() OVER (ORDER BY sale_price) AS row_num 87 | FROM product   88 | ``` 89 | 90 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0503.png) 91 | 92 | 93 | ## 5.2.2 聚合函数在窗口函数上的使用 94 | 95 | 聚合函数在开窗函数中的使用方法和之前的专用窗口函数一样,只是出来的结果是一个**累计**的聚合函数值。 96 | 97 | 运行以下代码: 98 | 99 | ```sql 100 | SELECT product_id 101 | ,product_name 102 | ,sale_price 103 | ,SUM(sale_price) OVER (ORDER BY product_id) AS current_sum 104 | ,AVG(sale_price) OVER (ORDER BY product_id) AS current_avg   105 | FROM product;   106 | ``` 107 | 108 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0504.png) 109 | 110 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0505.png) 111 | 112 | 可以看出,聚合函数结果是,按我们指定的排序,这里是product_id,**当前所在行及之前所有的行**的合计或均值。即累计到当前行的聚合。 113 | 114 | 115 | # 5.3 窗口函数的的应用 - 计算移动平均 116 | 117 | 在上面提到,聚合函数在窗口函数使用时,计算的是累积到当前行的所有的数据的聚合。 实际上,还可以指定更加详细的**汇总范围**。该汇总范围成为**框架(****frame****)。** 118 | 119 | 语法 120 | 121 | ```sql 122 | <窗口函数> OVER (ORDER BY <排序用列名> 123 | ROWS n PRECEDING )   124 | 125 | <窗口函数> OVER (ORDER BY <排序用列名> 126 | ROWS BETWEEN n PRECEDING AND n FOLLOWING) 127 | ``` 128 | PRECEDING(“之前”), 将框架指定为 “截止到之前 n 行”,加上自身行 129 | 130 | FOLLOWING(“之后”), 将框架指定为 “截止到之后 n 行”,加上自身行 131 | 132 | BETWEEN 1 PRECEDING AND 1 FOLLOWING,将框架指定为 “之前1行” + “之后1行” + “自身” 133 | 134 | 执行以下代码: 135 | 136 | ```sql 137 | SELECT product_id 138 | ,product_name 139 | ,sale_price 140 | ,AVG(sale_price) OVER (ORDER BY product_id 141 | ROWS 2 PRECEDING) AS moving_avg 142 | ,AVG(sale_price) OVER (ORDER BY product_id 143 | ROWS BETWEEN 1 PRECEDING 144 | AND 1 FOLLOWING) AS moving_avg 145 | FROM product   146 | ``` 147 | 148 | **执行结果:** 149 | 150 | 注意观察框架的范围。 151 | 152 | ROWS 2 PRECEDING: 153 | 154 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0506.png) 155 | 156 | ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING: 157 | 158 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0507.png) 159 | 160 | ## 5.3.1 窗口函数适用范围和注意事项 161 | 162 | * 原则上,窗口函数只能在SELECT子句中使用。 163 | * 窗口函数OVER 中的ORDER BY 子句并不会影响最终结果的排序。其只是用来决定窗口函数按何种顺序计算。 164 | # 5.4 GROUPING运算符 165 | 166 | ## 5.4.1 ROLLUP - 计算合计及小计 167 | 168 | 常规的GROUP BY 只能得到每个分类的小计,有时候还需要计算分类的合计,可以用 ROLLUP关键字。 169 | 170 | ```sql 171 | SELECT product_type 172 | ,regist_date 173 | ,SUM(sale_price) AS sum_price 174 | FROM product 175 | GROUP BY product_type, regist_date WITH ROLLUP   176 | ``` 177 | 得到的结果为: 178 | 179 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0508.png) 180 | 181 | ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0509.png) 182 | 183 | 这里ROLLUP 对product_type, regist_date两列进行合计汇总。结果实际上有三层聚合,如下图 模块3是常规的 GROUP BY 的结果,需要注意的是衣服 有个注册日期为空的,这是本来数据就存在日期为空的,不是对衣服类别的合计; 模块2和1是 ROLLUP 带来的合计,模块2是对产品种类的合计,模块1是对全部数据的总计。 184 | 185 | ROLLUP 可以对多列进行汇总求小计和合计。 186 | 187 | # ![图片](https://github.com/datawhalechina/team-learning-sql/blob/main/img/ch05/ch0510.png) 188 | 189 | # 练习题 190 | 191 | ## **5.1** 192 | 193 | 请说出针对本章中使用的 product(商品)表执行如下 SELECT 语句所能得到的结果。 194 | 195 | ```sql 196 | SELECT product_id 197 | ,product_name 198 | ,sale_price 199 | ,MAX(sale_price) OVER (ORDER BY product_id) AS Current_max_price 200 | FROM product 201 | ``` 202 | ## **5.2** 203 | 204 | 继续使用product表,计算出按照登记日期(regist_date)升序进行排列的各日期的销售单价(sale_price)的总额。排序是需要将登记日期为NULL 的“运动 T 恤”记录排在第 1 位(也就是将其看作比其他日期都早) 205 | 206 | ## **5.3** 207 | 208 | 思考题 209 | 210 | ① 窗口函数不指定PARTITION BY的效果是什么? 211 | 212 | ② 为什么说窗口函数只能在SELECT子句中使用?实际上,在ORDER BY 子句使用系统并不会报错。 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /Task06:综合练习.md: -------------------------------------------------------------------------------- 1 | # 练习一: 各部门工资最高的员工(难度:中等) 2 | 3 | 创建Employee 表,包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id。 4 | 5 | ```plain 6 | +----+-------+--------+--------------+ 7 | | Id | Name | Salary | DepartmentId | 8 | +----+-------+--------+--------------+ 9 | | 1 | Joe | 70000 | 1 | 10 | | 2 | Henry | 80000 | 2 | 11 | | 3 | Sam | 60000 | 2 | 12 | | 4 | Max | 90000 | 1 | 13 | +----+-------+--------+--------------+ 14 | ``` 15 | 创建Department 表,包含公司所有部门的信息。 16 | ```plain 17 | +----+----------+ 18 | | Id | Name | 19 | +----+----------+ 20 | | 1 | IT | 21 | | 2 | Sales | 22 | +----+----------+ 23 | ``` 24 | 编写一个 SQL 查询,找出每个部门工资最高的员工。例如,根据上述给定的表格,Max 在 IT 部门有最高工资,Henry 在 Sales 部门有最高工资。 25 | ```plain 26 | +------------+----------+--------+ 27 | | Department | Employee | Salary | 28 | +------------+----------+--------+ 29 | | IT | Max | 90000 | 30 | | Sales | Henry | 80000 | 31 | +------------+----------+--------+ 32 | ``` 33 | 34 | # 练习二: 换座位(难度:中等) 35 | 36 | 小美是一所中学的信息科技老师,她有一张 seat 座位表,平时用来储存学生名字和与他们相对应的座位 id。 37 | 38 | 其中纵列的**id**是连续递增的 39 | 40 | 小美想改变相邻俩学生的座位。 41 | 42 | 你能不能帮她写一个 SQL query 来输出小美想要的结果呢? 43 | 44 | 请创建如下所示seat表: 45 | 46 | **示例:** 47 | 48 | ```plain 49 | +---------+---------+ 50 | | id | student | 51 | +---------+---------+ 52 | | 1 | Abbot | 53 | | 2 | Doris | 54 | | 3 | Emerson | 55 | | 4 | Green | 56 | | 5 | Jeames | 57 | +---------+---------+ 58 | ``` 59 | 假如数据输入的是上表,则输出结果如下: 60 | ```plain 61 | +---------+---------+ 62 | | id | student | 63 | +---------+---------+ 64 | | 1 | Doris | 65 | | 2 | Abbot | 66 | | 3 | Green | 67 | | 4 | Emerson | 68 | | 5 | Jeames | 69 | +---------+---------+ 70 | ``` 71 | **注意:** 72 | 如果学生人数是奇数,则不需要改变最后一个同学的座位。 73 | 74 | 75 | # 练习三: 分数排名(难度:中等) 76 | 77 | 编写一个 SQL 查询来实现分数排名。如果两个分数相同,则两个分数排名(Rank)相同。请注意,平分后的下一个名次应该是下一个连续的整数值。换句话说,名次之间不应该有“间隔”。 78 | 79 | 创建以下score表: 80 | 81 | ```plain 82 | +----+-------+ 83 | | Id | Score | 84 | +----+-------+ 85 | | 1 | 3.50 | 86 | | 2 | 3.65 | 87 | | 3 | 4.00 | 88 | | 4 | 3.85 | 89 | | 5 | 4.00 | 90 | | 6 | 3.65 | 91 | +----+-------+ 92 | ``` 93 | 例如,根据上述给定的 Scores 表,你的查询应该返回(按分数从高到低排列): 94 | ```plain 95 | +-------+------+ 96 | | Score | Rank | 97 | +-------+------+ 98 | | 4.00 | 1 | 99 | | 4.00 | 1 | 100 | | 3.85 | 2 | 101 | | 3.65 | 3 | 102 | | 3.65 | 3 | 103 | | 3.50 | 4 | 104 | +-------+------+ 105 | ``` 106 | # 练习四:连续出现的数字(难度:中等) 107 | 108 | 编写一个 SQL 查询,查找所有至少连续出现三次的数字。 109 | 110 | ```plain 111 | +----+-----+ 112 | | Id | Num | 113 | +----+-----+ 114 | | 1  |  1  | 115 | | 2  |  1  | 116 | | 3  |  1  | 117 | | 4  |  2  | 118 | | 5  |  1  | 119 | | 6  |  2  | 120 | | 7  |  2  | 121 | +----+-----+ 122 | ``` 123 | 例如,给定上面的 Logs 表, 1 是唯一连续出现至少三次的数字。 124 | ```plain 125 | +-----------------+ 126 | | ConsecutiveNums | 127 | +-----------------+ 128 | | 1               | 129 | +-----------------+ 130 | ``` 131 | # 练习五:树节点 (难度:中等) 132 | 133 | 对于**tree**表,*id*是树节点的标识,*p_id*是其父节点的*id*。 134 | 135 | ```plain 136 | +----+------+ 137 | | id | p_id | 138 | +----+------+ 139 | | 1 | null | 140 | | 2 | 1 | 141 | | 3 | 1 | 142 | | 4 | 2 | 143 | | 5 | 2 | 144 | +----+------+ 145 | ``` 146 | 每个节点都是以下三种类型中的一种: 147 | * Root: 如果节点是根节点。 148 | * Leaf: 如果节点是叶子节点。 149 | * Inner: 如果节点既不是根节点也不是叶子节点。 150 | 151 | 写一条查询语句打印节点id及对应的节点类型。按照节点id排序。上面例子的对应结果为: 152 | 153 | ```plain 154 | +----+------+ 155 | | id | Type | 156 | +----+------+ 157 | | 1 | Root | 158 | | 2 | Inner| 159 | | 3 | Leaf | 160 | | 4 | Leaf | 161 | | 5 | Leaf | 162 | +----+------+ 163 | ``` 164 | **说明** 165 | * 节点’1’是根节点,因为它的父节点为NULL,有’2’和’3’两个子节点。 166 | * 节点’2’是内部节点,因为它的父节点是’1’,有子节点’4’和’5’。 167 | * 节点’3’,‘4’,'5’是叶子节点,因为它们有父节点但没有子节点。 168 | 169 | 下面是树的图形: 170 | 171 | 1 172 | / \ 173 | 2 3 174 | / \ 175 | 4 5 176 | 177 | **注意** 178 | 179 | 如果一个树只有一个节点,只需要输出根节点属性。 180 | 181 | # 练习六:至少有五名直接下属的经理 (难度:中等) 182 | 183 | **Employee**表包含所有员工及其上级的信息。每位员工都有一个Id,并且还有一个对应主管的Id(ManagerId)。 184 | 185 | ```plain 186 | +------+----------+-----------+----------+ 187 | |Id |Name |Department |ManagerId | 188 | +------+----------+-----------+----------+ 189 | |101 |John |A |null | 190 | |102 |Dan |A |101 | 191 | |103 |James |A |101 | 192 | |104 |Amy |A |101 | 193 | |105 |Anne |A |101 | 194 | |106 |Ron |B |101 | 195 | +------+----------+-----------+----------+ 196 | ``` 197 | 针对**Employee**表,写一条SQL语句找出有5个下属的主管。对于上面的表,结果应输出: 198 | 199 | ```plain 200 | +-------+ 201 | | Name | 202 | +-------+ 203 | | John | 204 | +-------+ 205 | ``` 206 | **注意:** 207 | 208 | 没有人向自己汇报。 209 | 210 | 211 | # 练习七: 分数排名 (难度:中等) 212 | 213 | 练习三的分数表,实现排名功能,但是排名需要是非连续的,如下: 214 | 215 | ```plain 216 | +-------+------+ 217 | | Score | Rank | 218 | +-------+------+ 219 | | 4.00 | 1 | 220 | | 4.00 | 1 | 221 | | 3.85 | 3 | 222 | | 3.65 | 4 | 223 | | 3.65 | 4 | 224 | | 3.50 | 6 | 225 | +-------+------ 226 | ``` 227 | # 练习八:查询回答率最高的问题 (难度:中等) 228 | 229 | 求出**survey_log**表中回答率最高的问题,表格的字段有:**uid, action, question_id, answer_id, q_num, timestamp**。 230 | 231 | uid是用户id;action的值为:“show”, “answer”, “skip”;当action是"answer"时,answer_id不为空,相反,当action是"show"和"skip"时为空(null);q_num是问题的数字序号。 232 | 233 | 写一条sql语句找出回答率最高的问题。 234 | 235 | **举例:** 236 | 237 | **输入** 238 | 239 | | uid  | action | question_id  | answer_id  | q_num|timestamp  | 240 | |:----|:----|:----|:----|:----|:----| 241 | |5| show      |285| null       |1|123| 242 | |5| answer    |285|124124|1|124| 243 | |5| show      |369| null       |2|125| 244 | |5| skip      |369| null       |2|126| 245 | 246 | **输出** 247 | 248 | |survey_log | 249 | |:----| 250 | |285 | 251 | 252 | **说明** 253 | 254 | 问题285的回答率为1/1,然而问题369的回答率是0/1,所以输出是285。 255 | 256 | **注意:**最高回答率的意思是:同一个问题出现的次数中回答的比例。 257 | 258 | # 练习九:各部门前3高工资的员工(难度:中等) 259 | 260 | 将项目7中的employee表清空,重新插入以下数据(其实是多插入5,6两行): 261 | 262 | ```plain 263 | +----+-------+--------+--------------+ 264 | | Id | Name | Salary | DepartmentId | 265 | +----+-------+--------+--------------+ 266 | | 1 | Joe | 70000 | 1 | 267 | | 2 | Henry | 80000 | 2 | 268 | | 3 | Sam | 60000 | 2 | 269 | | 4 | Max | 90000 | 1 | 270 | | 5 | Janet | 69000 | 1 | 271 | | 6 | Randy | 85000 | 1 | 272 | +----+-------+--------+--------------+ 273 | ``` 274 | 编写一个 SQL 查询,找出每个部门工资前三高的员工。例如,根据上述给定的表格,查询结果应返回: 275 | ```plain 276 | +------------+----------+--------+ 277 | | Department | Employee | Salary | 278 | +------------+----------+--------+ 279 | | IT | Max | 90000 | 280 | | IT | Randy | 85000 | 281 | | IT | Joe | 70000 | 282 | | Sales | Henry | 80000 | 283 | | Sales | Sam | 60000 | 284 | +------------+----------+--------+ 285 | ``` 286 | 此外,请考虑实现各部门前N高工资的员工功能。 287 | 288 | # 练习十:平面上最近距离 (难度: 困难) 289 | 290 | **point_2d**表包含一个平面内一些点(超过两个)的坐标值(x,y)。 291 | 292 | 写一条查询语句求出这些点中的最短距离并保留2位小数。 293 | 294 | ```plain 295 | |x   | y  | 296 | |----|----| 297 | | -1 | -1 | 298 | | 0 | 0 | 299 | | -1 | -2 | 300 | ``` 301 | 最短距离是1,从点(-1,-1)到点(-1,-2)。所以输出结果为: 302 | 303 | | shortest | 304 | 305 | 1.00 306 | 307 | ```plain 308 | +--------+ 309 | |shortest| 310 | +--------+ 311 | |1.00 | 312 | +--------+ 313 | ``` 314 | **注意:**所有点的最大距离小于10000。 315 | 316 | # 练习十一:行程和用户(难度:困难) 317 | 318 | Trips 表中存所有出租车的行程信息。每段行程有唯一键 Id,Client_Id 和 Driver_Id 是 Users 表中 Users_Id 的外键。Status 是枚举类型,枚举成员为 (‘completed’, ‘cancelled_by_driver’, ‘cancelled_by_client’)。 319 | 320 | | Id | Client_Id | Driver_Id | City_Id |        Status      |Request_at| 321 | |:----|:----|:----|:----|:----|:----| 322 | |1|1|10|1|     completed      |2013-10-1| 323 | |2|2|11|1| cancelled_by_driver|2013-10-1| 324 | |3|3|12|6|     completed      |2013-10-1| 325 | |4|4|13|6| cancelled_by_client|2013-10-1| 326 | |5|1|10|1|     completed      |2013-10-2| 327 | |6|2|11|6|     completed      |2013-10-2| 328 | |7|3|12|6|     completed      |2013-10-2| 329 | |8|2|12|12|     completed      |2013-10-3| 330 | |9|3|10|12|     completed      |2013-10-3| 331 | |10|4|13|12| cancelled_by_driver|2013-10-3| 332 | 333 | Users 表存所有用户。每个用户有唯一键 Users_Id。Banned 表示这个用户是否被禁止,Role 则是一个表示(‘client’, ‘driver’, ‘partner’)的枚举类型。 334 | 335 | ```plain 336 | +----------+--------+--------+ 337 | | Users_Id | Banned | Role | 338 | +----------+--------+--------+ 339 | | 1 | No | client | 340 | | 2 | Yes | client | 341 | | 3 | No | client | 342 | | 4 | No | client | 343 | | 10 | No | driver | 344 | | 11 | No | driver | 345 | | 12 | No | driver | 346 | | 13 | No | driver | 347 | +----------+--------+--------+ 348 | ``` 349 | 写一段 SQL 语句查出**2013年10月1日**至**2013年10月3日**期间非禁止用户的取消率。基于上表,你的 SQL 语句应返回如下结果,取消率(Cancellation Rate)保留两位小数。 350 | ```plain 351 | +------------+-------------------+ 352 | | Day | Cancellation Rate | 353 | +------------+-------------------+ 354 | | 2013-10-01 | 0.33 | 355 | | 2013-10-02 | 0.00 | 356 | | 2013-10-03 | 0.50 | 357 | +------------+-------------------+ 358 | ``` 359 | 360 | 361 | 362 | 363 | 364 | -------------------------------------------------------------------------------- /img/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/00 SQL基础课程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/00 SQL基础课程.png -------------------------------------------------------------------------------- /img/ch00/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch00/ch0001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0001.png -------------------------------------------------------------------------------- /img/ch00/ch0002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0002.png -------------------------------------------------------------------------------- /img/ch00/ch0003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0003.png -------------------------------------------------------------------------------- /img/ch00/ch0004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0004.png -------------------------------------------------------------------------------- /img/ch00/ch0005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0005.png -------------------------------------------------------------------------------- /img/ch00/ch0006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0006.png -------------------------------------------------------------------------------- /img/ch00/ch0007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0007.png -------------------------------------------------------------------------------- /img/ch00/ch0008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0008.png -------------------------------------------------------------------------------- /img/ch00/ch0009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0009.png -------------------------------------------------------------------------------- /img/ch00/ch0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0010.png -------------------------------------------------------------------------------- /img/ch00/ch0011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0011.png -------------------------------------------------------------------------------- /img/ch00/ch0012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0012.png -------------------------------------------------------------------------------- /img/ch00/ch0013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0013.png -------------------------------------------------------------------------------- /img/ch00/ch0014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0014.png -------------------------------------------------------------------------------- /img/ch00/ch0015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0015.png -------------------------------------------------------------------------------- /img/ch00/ch0016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0016.png -------------------------------------------------------------------------------- /img/ch00/ch0017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0017.png -------------------------------------------------------------------------------- /img/ch00/ch0018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0018.png -------------------------------------------------------------------------------- /img/ch00/ch0019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0019.png -------------------------------------------------------------------------------- /img/ch00/ch0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0020.png -------------------------------------------------------------------------------- /img/ch00/ch0021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0021.png -------------------------------------------------------------------------------- /img/ch00/ch0022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0022.png -------------------------------------------------------------------------------- /img/ch00/ch0023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0023.png -------------------------------------------------------------------------------- /img/ch00/ch0024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0024.png -------------------------------------------------------------------------------- /img/ch00/ch0025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0025.png -------------------------------------------------------------------------------- /img/ch00/ch0026.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0026.png -------------------------------------------------------------------------------- /img/ch00/ch0027.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0027.png -------------------------------------------------------------------------------- /img/ch00/ch0028.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0028.png -------------------------------------------------------------------------------- /img/ch00/ch0029.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0029.png -------------------------------------------------------------------------------- /img/ch00/ch0030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0030.png -------------------------------------------------------------------------------- /img/ch00/ch0031.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0031.png -------------------------------------------------------------------------------- /img/ch00/ch0032.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0032.png -------------------------------------------------------------------------------- /img/ch00/ch0033.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0033.png -------------------------------------------------------------------------------- /img/ch00/ch0034.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0034.png -------------------------------------------------------------------------------- /img/ch00/ch0035.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0035.png -------------------------------------------------------------------------------- /img/ch00/ch0036.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0036.png -------------------------------------------------------------------------------- /img/ch00/ch0037.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0037.png -------------------------------------------------------------------------------- /img/ch00/ch0038.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0038.png -------------------------------------------------------------------------------- /img/ch00/ch0039.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0039.png -------------------------------------------------------------------------------- /img/ch00/ch0040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0040.png -------------------------------------------------------------------------------- /img/ch00/ch0041.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0041.png -------------------------------------------------------------------------------- /img/ch00/ch0042.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0042.png -------------------------------------------------------------------------------- /img/ch00/ch0043.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0043.png -------------------------------------------------------------------------------- /img/ch00/ch0044.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0044.png -------------------------------------------------------------------------------- /img/ch00/ch0045.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0045.png -------------------------------------------------------------------------------- /img/ch00/ch0046.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0046.png -------------------------------------------------------------------------------- /img/ch00/ch0047.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0047.png -------------------------------------------------------------------------------- /img/ch00/ch0048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0048.png -------------------------------------------------------------------------------- /img/ch00/ch0049.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0049.png -------------------------------------------------------------------------------- /img/ch00/ch0050.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0050.png -------------------------------------------------------------------------------- /img/ch00/ch0051.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0051.png -------------------------------------------------------------------------------- /img/ch00/ch0052.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0052.png -------------------------------------------------------------------------------- /img/ch00/ch0053.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0053.png -------------------------------------------------------------------------------- /img/ch00/ch0054.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0054.png -------------------------------------------------------------------------------- /img/ch00/ch00541.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch00541.png -------------------------------------------------------------------------------- /img/ch00/ch0055.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0055.png -------------------------------------------------------------------------------- /img/ch00/ch0056.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0056.png -------------------------------------------------------------------------------- /img/ch00/ch0057.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0057.png -------------------------------------------------------------------------------- /img/ch00/ch0058.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0058.png -------------------------------------------------------------------------------- /img/ch00/ch0059.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0059.png -------------------------------------------------------------------------------- /img/ch00/ch0060.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0060.png -------------------------------------------------------------------------------- /img/ch00/ch0061.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0061.png -------------------------------------------------------------------------------- /img/ch00/ch0062.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0062.png -------------------------------------------------------------------------------- /img/ch00/ch0063.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0063.png -------------------------------------------------------------------------------- /img/ch00/ch0064.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0064.png -------------------------------------------------------------------------------- /img/ch00/ch0065.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0065.png -------------------------------------------------------------------------------- /img/ch00/ch0066.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0066.png -------------------------------------------------------------------------------- /img/ch00/ch0067.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0067.png -------------------------------------------------------------------------------- /img/ch00/ch0068.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0068.png -------------------------------------------------------------------------------- /img/ch00/ch0069.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0069.png -------------------------------------------------------------------------------- /img/ch00/ch0070.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0070.png -------------------------------------------------------------------------------- /img/ch00/ch0071.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0071.png -------------------------------------------------------------------------------- /img/ch00/ch0072.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0072.png -------------------------------------------------------------------------------- /img/ch00/ch0073.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0073.png -------------------------------------------------------------------------------- /img/ch00/ch0074.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0074.png -------------------------------------------------------------------------------- /img/ch00/ch0075.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch00/ch0075.png -------------------------------------------------------------------------------- /img/ch01/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch01/ch01.01系统结构.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch01/ch01.01系统结构.jpg -------------------------------------------------------------------------------- /img/ch01/ch01.02表的示例.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch01/ch01.02表的示例.jpg -------------------------------------------------------------------------------- /img/ch01/ch01.03商品表和列名对应关系.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch01/ch01.03商品表和列名对应关系.png -------------------------------------------------------------------------------- /img/ch01/ch01.04习题1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch01/ch01.04习题1.png -------------------------------------------------------------------------------- /img/ch02/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch02/ch02.01and.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch02/ch02.01and.png -------------------------------------------------------------------------------- /img/ch02/ch02.02or.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch02/ch02.02or.png -------------------------------------------------------------------------------- /img/ch02/ch02.03true.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch02/ch02.03true.png -------------------------------------------------------------------------------- /img/ch02/ch02.04true2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch02/ch02.04true2.png -------------------------------------------------------------------------------- /img/ch02/ch02.05true3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch02/ch02.05true3.png -------------------------------------------------------------------------------- /img/ch02/ch02.06cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch02/ch02.06cut.png -------------------------------------------------------------------------------- /img/ch02/ch02.07groupby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch02/ch02.07groupby.png -------------------------------------------------------------------------------- /img/ch02/ch02.08test26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch02/ch02.08test26.png -------------------------------------------------------------------------------- /img/ch02/ch02.09test27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch02/ch02.09test27.png -------------------------------------------------------------------------------- /img/ch03/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch03/ch03.01view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.01view.png -------------------------------------------------------------------------------- /img/ch03/ch03.02view2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.02view2.png -------------------------------------------------------------------------------- /img/ch03/ch03.03view3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.03view3.png -------------------------------------------------------------------------------- /img/ch03/ch03.04view4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.04view4.png -------------------------------------------------------------------------------- /img/ch03/ch03.05result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.05result.png -------------------------------------------------------------------------------- /img/ch03/ch03.06productsum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.06productsum.png -------------------------------------------------------------------------------- /img/ch03/ch03.07productsum2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.07productsum2.png -------------------------------------------------------------------------------- /img/ch03/ch03.08productsumsrc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.08productsumsrc.png -------------------------------------------------------------------------------- /img/ch03/ch03.09case.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.09case.png -------------------------------------------------------------------------------- /img/ch03/ch03.10function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.10function.png -------------------------------------------------------------------------------- /img/ch03/ch03.11casewhen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.11casewhen1.png -------------------------------------------------------------------------------- /img/ch03/ch03.12casewhen2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch03/ch03.12casewhen2.png -------------------------------------------------------------------------------- /img/ch04/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch04/ch04.01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.01.png -------------------------------------------------------------------------------- /img/ch04/ch04.02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.02.png -------------------------------------------------------------------------------- /img/ch04/ch04.03union.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.03union.png -------------------------------------------------------------------------------- /img/ch04/ch04.04result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.04result.png -------------------------------------------------------------------------------- /img/ch04/ch04.05result2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.05result2.png -------------------------------------------------------------------------------- /img/ch04/ch04.06result3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.06result3.png -------------------------------------------------------------------------------- /img/ch04/ch04.07result4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.07result4.png -------------------------------------------------------------------------------- /img/ch04/ch04.08result5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.08result5.png -------------------------------------------------------------------------------- /img/ch04/ch04.09except.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.09except.png -------------------------------------------------------------------------------- /img/ch04/ch04.10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.10.png -------------------------------------------------------------------------------- /img/ch04/ch04.11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.11.png -------------------------------------------------------------------------------- /img/ch04/ch04.12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.12.png -------------------------------------------------------------------------------- /img/ch04/ch04.13join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.13join.png -------------------------------------------------------------------------------- /img/ch04/ch04.14tb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.14tb.png -------------------------------------------------------------------------------- /img/ch04/ch04.15shopproduct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.15shopproduct.png -------------------------------------------------------------------------------- /img/ch04/ch04.16tb73.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.16tb73.png -------------------------------------------------------------------------------- /img/ch04/ch04.17result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.17result.png -------------------------------------------------------------------------------- /img/ch04/ch04.18result2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.18result2.png -------------------------------------------------------------------------------- /img/ch04/ch04.19result3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.19result3.png -------------------------------------------------------------------------------- /img/ch04/ch04.20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.20.png -------------------------------------------------------------------------------- /img/ch04/ch04.21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.21.png -------------------------------------------------------------------------------- /img/ch04/ch04.22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.22.png -------------------------------------------------------------------------------- /img/ch04/ch04.23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.23.png -------------------------------------------------------------------------------- /img/ch04/ch04.24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.24.png -------------------------------------------------------------------------------- /img/ch04/ch04.25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.25.png -------------------------------------------------------------------------------- /img/ch04/ch04.26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.26.png -------------------------------------------------------------------------------- /img/ch04/ch04.27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.27.png -------------------------------------------------------------------------------- /img/ch04/ch04.28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.28.png -------------------------------------------------------------------------------- /img/ch04/ch04.29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.29.png -------------------------------------------------------------------------------- /img/ch04/ch04.30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.30.png -------------------------------------------------------------------------------- /img/ch04/ch04.31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.31.png -------------------------------------------------------------------------------- /img/ch04/ch04.32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.32.png -------------------------------------------------------------------------------- /img/ch04/ch04.33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.33.png -------------------------------------------------------------------------------- /img/ch04/ch04.34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.34.png -------------------------------------------------------------------------------- /img/ch04/ch04.35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.35.png -------------------------------------------------------------------------------- /img/ch04/ch04.36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.36.png -------------------------------------------------------------------------------- /img/ch04/ch04.37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch04/ch04.37.png -------------------------------------------------------------------------------- /img/ch05/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch05/ch0501.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0501.png -------------------------------------------------------------------------------- /img/ch05/ch0502.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0502.png -------------------------------------------------------------------------------- /img/ch05/ch0503.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0503.png -------------------------------------------------------------------------------- /img/ch05/ch0504.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0504.png -------------------------------------------------------------------------------- /img/ch05/ch0505.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0505.png -------------------------------------------------------------------------------- /img/ch05/ch0506.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0506.png -------------------------------------------------------------------------------- /img/ch05/ch0507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0507.png -------------------------------------------------------------------------------- /img/ch05/ch0508.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0508.png -------------------------------------------------------------------------------- /img/ch05/ch0509.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0509.png -------------------------------------------------------------------------------- /img/ch05/ch0510.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/ch05/ch0510.png -------------------------------------------------------------------------------- /img/datawhale_code.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/team-learning-sql/b3208831249a361292380d4655f5b7280cbff51c/img/datawhale_code.jpeg -------------------------------------------------------------------------------- /shop.sql: -------------------------------------------------------------------------------- 1 | /* v 9.08 2 | SQL脚本的一些要点: 3 | 0.存储引擎使用 InnoDB, 字符集改为 utf8mb4 以更好地支持中文. 4 | 1.所有表名所使用的英文字母都改为小写(后续章节中,SQL查询中的表名也需要相应修改为小写) 5 | 2.所有列名所使用的英文字母确认为小写(后续章节中,SQL查询中的列名也需要相应修改为小写) 6 | 3.存在问题的数据, 例如 inventoryproduct 表的inventory_id列应为P开头的, 已修正为正确的数据. 7 | 4.需测试SQL脚本在命令行及各个客户端中是否能被正确执行. 8 | * MySQL Workbench 已测试通过 9 | * DBeaver 已测试通过(使用"执行SQL脚本(CTR+x)") 10 | * HeidiSQL 已测试通过 11 | * navicat 已测试通过 12 | * sqlyog 已测试通过 13 | * 命令行 测试未通过. 插入中文数据时提示" Data too long for column 'product_name' at row 1" 14 | */ 15 | CREATE DATABASE /*!32312 IF NOT EXISTS*/`shop` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; 16 | 17 | USE `shop`; 18 | 19 | /*Table structure for table `chars` */ 20 | 21 | DROP TABLE IF EXISTS `chars`; 22 | 23 | CREATE TABLE `chars` ( 24 | `chr` char(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 25 | PRIMARY KEY (`chr`) 26 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 27 | 28 | /*Data for the table `chars` */ 29 | 30 | insert into `chars`(`chr`) values ('1'),('10'),('11'),('2'),('222'),('3'); 31 | 32 | /*Table structure for table `empskills` */ 33 | 34 | DROP TABLE IF EXISTS `empskills`; 35 | 36 | CREATE TABLE `empskills` ( 37 | `emp` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 38 | `skill` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 39 | PRIMARY KEY (`emp`,`skill`) 40 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 41 | 42 | /*Data for the table `empskills` */ 43 | 44 | insert into `empskills`(`emp`,`skill`) values ('平井','C++'),('平井','Oracle'),('平井','Perl'),('平井','PHP'),('平井','UNIX'),('渡来','Oracle'),('相田','C#'),('相田','Java'),('相田','Oracle'),('相田','UNIX'),('神崎','Java'),('神崎','Oracle'),('神崎','UNIX'),('若田部','Perl'); 45 | 46 | /*Table structure for table `inventoryproduct` */ 47 | 48 | DROP TABLE IF EXISTS `inventoryproduct`; 49 | 50 | CREATE TABLE `inventoryproduct` ( 51 | `inventory_id` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 52 | `product_id` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 53 | `inventory_quantity` int NOT NULL, 54 | PRIMARY KEY (`inventory_id`,`product_id`) 55 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 56 | 57 | /*Data for the table `inventoryproduct` */ 58 | 59 | insert into `inventoryproduct`(`inventory_id`,`product_id`,`inventory_quantity`) values ('P001','0001',0),('P001','0002',120),('P001','0003',200),('P001','0004',3),('P001','0005',0),('P001','0006',99),('P001','0007',999),('P001','0008',200),('P002','0001',10),('P002','0002',25),('P002','0003',34),('P002','0004',19),('P002','0005',99),('P002','0006',0),('P002','0007',0),('P002','0008',18); 60 | 61 | /*Table structure for table `product` */ 62 | 63 | DROP TABLE IF EXISTS `product`; 64 | 65 | CREATE TABLE `product` ( 66 | `product_id` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 67 | `product_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 68 | `product_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 69 | `sale_price` int DEFAULT NULL, 70 | `purchase_price` int DEFAULT NULL, 71 | `regist_date` date DEFAULT NULL, 72 | PRIMARY KEY (`product_id`) 73 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 74 | 75 | /*Data for the table `product` */ 76 | 77 | insert into `product`(`product_id`,`product_name`,`product_type`,`sale_price`,`purchase_price`,`regist_date`) values ('0001','T恤','衣服',1000,500,'2009-09-20'),('0002','打孔器','办公用品',500,320,'2009-09-11'),('0003','运动T恤','衣服',4000,2800,NULL),('0004','菜刀','厨房用具',3000,2800,'2009-09-20'),('0005','高压锅','厨房用具',6800,5000,'2009-01-15'),('0006','叉子','厨房用具',500,NULL,'2009-09-20'),('0007','擦菜板','厨房用具',880,790,'2008-04-28'),('0008','圆珠笔','办公用品',100,NULL,'2009-11-11'); 78 | 79 | /*Table structure for table `product2` */ 80 | 81 | DROP TABLE IF EXISTS `product2`; 82 | 83 | CREATE TABLE `product2` ( 84 | `product_id` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 85 | `product_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 86 | `product_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 87 | `sale_price` int DEFAULT NULL, 88 | `purchase_price` int DEFAULT NULL, 89 | `regist_date` date DEFAULT NULL, 90 | PRIMARY KEY (`product_id`) 91 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 92 | 93 | /*Data for the table `product2` */ 94 | 95 | insert into `product2`(`product_id`,`product_name`,`product_type`,`sale_price`,`purchase_price`,`regist_date`) values ('0001','T恤','衣服',1000,500,'2009-09-20'),('0002','打孔器','办公用品',500,320,'2009-09-11'),('0003','运动T恤','衣服',4000,2800,NULL),('0009','手套','衣服',800,500,NULL),('0010','水壶','厨房用具',2000,1700,'2009-09-20'); 96 | 97 | /*Table structure for table `productcopy` */ 98 | 99 | DROP TABLE IF EXISTS `productcopy`; 100 | 101 | CREATE TABLE `productcopy` ( 102 | `product_id` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 103 | `product_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 104 | `product_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 105 | `sale_price` int DEFAULT NULL, 106 | `purchase_price` int DEFAULT NULL, 107 | `regist_date` date DEFAULT NULL, 108 | PRIMARY KEY (`product_id`) 109 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 110 | 111 | /*Data for the table `productcopy` */ 112 | 113 | /*Table structure for table `productins` */ 114 | 115 | DROP TABLE IF EXISTS `productins`; 116 | 117 | CREATE TABLE `productins` ( 118 | `product_id` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 119 | `product_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 120 | `product_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 121 | `sale_price` int DEFAULT '0', 122 | `purchase_date` int DEFAULT NULL, 123 | `regist_date` date DEFAULT NULL, 124 | PRIMARY KEY (`product_id`) 125 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 126 | 127 | /*Data for the table `productins` */ 128 | 129 | /*Table structure for table `producttype` */ 130 | 131 | DROP TABLE IF EXISTS `producttype`; 132 | 133 | CREATE TABLE `producttype` ( 134 | `product_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 135 | `sum_sale_price` int DEFAULT NULL, 136 | `sum_purchase_price` int DEFAULT NULL, 137 | PRIMARY KEY (`product_type`) 138 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 139 | 140 | /*Data for the table `producttype` */ 141 | 142 | /*Table structure for table `samplelike` */ 143 | 144 | DROP TABLE IF EXISTS `samplelike`; 145 | 146 | CREATE TABLE `samplelike` ( 147 | `strcol` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 148 | PRIMARY KEY (`strcol`) 149 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 150 | 151 | /*Data for the table `samplelike` */ 152 | 153 | insert into `samplelike`(`strcol`) values ('abcdd'),('abcddd'),('abddc'),('abdddc'),('ddabc'),('dddabc'); 154 | 155 | /*Table structure for table `samplemath` */ 156 | 157 | DROP TABLE IF EXISTS `samplemath`; 158 | 159 | CREATE TABLE `samplemath` ( 160 | `m` decimal(10,3) DEFAULT NULL, 161 | `n` int DEFAULT NULL, 162 | `p` int DEFAULT NULL 163 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 164 | 165 | /*Data for the table `samplemath` */ 166 | 167 | insert into `samplemath`(`m`,`n`,`p`) values ('500.000',0,NULL),('-180.000',0,NULL),(NULL,NULL,NULL),(NULL,7,3),(NULL,5,2),(NULL,4,NULL),('8.000',NULL,3),('2.270',1,NULL),('5.555',2,NULL),(NULL,1,NULL),('8.760',NULL,NULL); 168 | 169 | /*Table structure for table `samplestr` */ 170 | 171 | DROP TABLE IF EXISTS `samplestr`; 172 | 173 | CREATE TABLE `samplestr` ( 174 | `str1` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, 175 | `str2` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, 176 | `str3` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL 177 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 178 | 179 | /*Data for the table `samplestr` */ 180 | 181 | insert into `samplestr`(`str1`,`str2`,`str3`) values ('opx','rt',NULL),('abc','def',NULL),('山田','太郎','是我'),('aaa',NULL,NULL),(NULL,'xyz',NULL),('@!#$%',NULL,NULL),('ABC',NULL,NULL),('aBC',NULL,NULL),('abc太郎','abc','ABC'),('abcdefabc','abc','ABC'),('micmic','i','I'); 182 | 183 | /*Table structure for table `shopproduct` */ 184 | 185 | DROP TABLE IF EXISTS `shopproduct`; 186 | 187 | CREATE TABLE `shopproduct` ( 188 | `shop_id` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 189 | `shop_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 190 | `product_id` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 191 | `quantity` int NOT NULL, 192 | PRIMARY KEY (`shop_id`,`product_id`) 193 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 194 | 195 | /*Data for the table `shopproduct` */ 196 | 197 | insert into `shopproduct`(`shop_id`,`shop_name`,`product_id`,`quantity`) values ('000A','东京','0001',30),('000A','东京','0002',50),('000A','东京','0003',15),('000B','名古屋','0002',30),('000B','名古屋','0003',120),('000B','名古屋','0004',20),('000B','名古屋','0006',10),('000B','名古屋','0007',40),('000C','大阪','0003',20),('000C','大阪','0004',50),('000C','大阪','0006',90),('000C','大阪','0007',70),('000D','福冈','0001',100); 198 | 199 | /*Table structure for table `skills` */ 200 | 201 | DROP TABLE IF EXISTS `skills`; 202 | 203 | CREATE TABLE `skills` ( 204 | `skill` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, 205 | PRIMARY KEY (`skill`) 206 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 207 | 208 | /*Data for the table `skills` */ 209 | 210 | insert into `skills`(`skill`) values ('Java'),('Oracle'),('UNIX'); --------------------------------------------------------------------------------