├── README.md ├── ch00_环境搭建.md ├── ch01_初识数据库.md ├── ch02_基础查询与排序.md ├── ch03_复杂一点的查询.md ├── ch04_集合运算.md ├── ch05_SQL高级处理.md ├── ch06_决胜秋招.md ├── img ├── .gitkeep ├── 00 SQL基础课程.png ├── Question_C │ ├── .gitkeep │ ├── C05A.jpg │ └── C05B.jpg ├── ch00 │ ├── .gitkeep │ ├── ch0001.png │ ├── ch0002.png │ ├── ch0003.png │ ├── ch0004.png │ ├── ch0005-mysql-install-custom.png │ ├── ch0005-mysql-install-custom2.png │ ├── ch0005.png │ ├── ch0005A.png │ ├── ch0005B.png │ ├── ch0005C.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 │ ├── ubuntu-mysql-1.png │ ├── ubuntu-mysql-2.png │ ├── ubuntu-mysql-3.png │ ├── ubuntu-mysql-4.png │ ├── ubuntu-mysql-5.png │ ├── ubuntu-mysql-6.png │ ├── ubuntu-mysql-7.png │ ├── ubuntu-mysql-8.png │ ├── ubuntu-mysql-9.png │ ├── ubuntu-mysql-a.png │ └── ubuntu-mysql-b.png ├── ch01 │ ├── .gitkeep │ ├── ch01.01系统结构.jpg │ ├── ch01.02表的示例.jpg │ ├── ch01.03商品表和列名对应关系.png │ └── ch01.04习题1.png ├── ch02 │ ├── .gitkeep │ ├── ch02.00-not-230.png │ ├── ch02.00-not-231.png │ ├── ch02.01and.png │ ├── ch02.02or.png │ ├── ch02.03true.png │ ├── ch02.04true2.png │ ├── ch02.05true3.png │ ├── ch02.06cut.png │ ├── ch02.07_null_first1.jpg │ ├── ch02.07_null_first2.jpg │ ├── ch02.07_null_first3.jpg │ ├── ch02.07_null_first4.jpg │ ├── ch02.07_null_last1.jpg │ ├── ch02.07_null_last2.jpg │ ├── ch02.07_null_last3.jpg │ ├── ch02.07_null_last4.jpg │ ├── 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.10-1-sale_price_avg.png │ ├── ch03.10-2-sale_price_avg_type.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.05result2_new.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 │ ├── ch0511MySQL-Prepared-Statement.png │ ├── ch0512-prepare-result1.png │ ├── ch0513-prepare-result2.png │ └── ch0514-question5.4v2.png ├── datawhale_code.jpeg └── feishu.jpg ├── materials ├── .gitignore ├── SQL基础教程-V2.0.pdf ├── create_table_sql │ ├── shop.sql │ ├── world.sql │ └── 决胜秋招-建表语句.sql ├── free_navicat_download │ └── baidu_cloud_url.md ├── readme.md ├── 参考答案.md ├── 附录1:SQL语法规范.md └── 附录2: [选学] 使用 Python 连接 MySQL.md └── practice-questions ├── .gitignore └── question_list.md /README.md: -------------------------------------------------------------------------------- 1 | # wonderful-sql 2 | 3 | Follow me,从 0 到 1 掌握 SQL。 4 | 5 | # 项目由来 6 | 7 | 随着社会的快速发展,各类企业数字化转型迫在眉睫,SQL 应用能力日趋重要。 在诸多领域中 SQL 应用广泛,数据分析、开发、测试、维护、产品经理等都有可能会用到SQL,而在学校里系统性讲授 SQL 的课程较少,但是面试及日常工作中却经常会涉及到 SQL。这就要求我们提前掌握这一技能。笔者在多年的学习过程中,总结了一些方式方法。受 datawhale 开源理念影响,我非常愿意将我所掌握的知识分享给别人,于是乎,我就发起了这个项目,联合其他几位组织成员,结合经典图书《SQL基础教程》加上团队成员的经验教训,形成了本课程,希望可以帮助你更好的了解和掌握 SQL。 8 | 9 | 考虑到易用性和普及度,课程内容采用`MySql` 数据库进行介绍,具体的目录参见下方,每个章节附带了练习题,最后几个章节是整理的一些面试题,顺利完成本课程学习后,可以帮你更好的应对 SQL 相关的面试或者更好的开展 SQL 相关的日常工作。 10 | 11 | 本课程所涉及的各类文件存储在 `./materials` 目录下,如果有疑问、建议或者勘误信息,请提交`issue` 或者 `Pull request` 给我们,我们将及时响应。 12 | 13 | ## 特别说明 14 | 15 | 1、原则上所有 task 打卡时需要提供文章链接(总结学习内容,完成课后作业),task06 要求必须提交文章链接,不提交视为水卡。 16 | 17 | 2、组队学习期间关闭参考答案访问权限,其他时段开放访问权限(组队时段大概是每个月后两周,详见 `Datawhale` 公众号当月组队学习内容介绍)。 18 | 19 | 3、仓库下载便捷方式:采用 **`Git Bash`** 工具,执行命令 `git clone https://github.com/datawhalechina/wonderful-sql` 可以较为快速的下载本仓库到本地,然后使用 markdown 工具打开(比如 Typora)。 20 | 21 | 4、**由于可能会进行组队学习,所以参考答案是不定期公开的,组队学习期间会收回查看权限,如未参加组队学习,但是想查看参考答案,可以通过如下链接添加我的飞书好友,私聊开通权限。** 22 | 23 | [我的飞书二维码](https://xz9235vqyp.feishu.cn/docx/CvtTdRHBSofqxUxGm5mc9j2VnTb) 24 | 25 | ## 课程目录 26 | 27 | * ch00:绪论 - 环境搭建 28 | - :white_check_mark: [1. MySQL 8.0 的安装](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%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) 29 | - :white_check_mark: [2. 连接 MySQL 并执行 SQL 查询](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%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) 30 | 31 | * ch01:初识数据库 32 | - :white_check_mark: [1.1 初识数据库](https://github.com/datawhalechina/wonderful-sql/blob/main/ch01:%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) 33 | - :white_check_mark: [1.2 初识SQL](https://github.com/datawhalechina/wonderful-sql/blob/main/ch01:%E5%88%9D%E8%AF%86%E6%95%B0%E6%8D%AE%E5%BA%93.md#12-%E5%88%9D%E8%AF%86-sql) 34 | - :white_check_mark: [参考答案链接](https://xz9235vqyp.feishu.cn/docs/doccnMduaNhilUIrlldFqmNWIzf) 35 | 36 | * ch02:基础查询与排序 37 | - :white_check_mark: [2.1 SELECT语句基础](https://github.com/datawhalechina/wonderful-sql/blob/main/ch02:%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) 38 | - :white_check_mark: [2.2 算术运算符和比较运算符](https://github.com/datawhalechina/wonderful-sql/blob/main/ch02:%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) 39 | - :white_check_mark: [2.3 逻辑运算符](https://github.com/datawhalechina/wonderful-sql/blob/main/ch02:%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) 40 | - :white_check_mark: [2.4 对表进行聚合查询](https://github.com/datawhalechina/wonderful-sql/blob/main/ch02:%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) 41 | - :white_check_mark: [2.5 对表进行分组](https://github.com/datawhalechina/wonderful-sql/blob/main/ch02:%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) 42 | - :white_check_mark: [2.6 为聚合结果指定条件](https://github.com/datawhalechina/wonderful-sql/blob/main/ch02:%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) 43 | - :white_check_mark: [参考答案链接](https://xz9235vqyp.feishu.cn/docs/doccnjASyISYXEDhI4W95Rycorh) 44 | 45 | * ch03:复杂一点的查询 46 | - :white_check_mark: [3.1 视图](https://github.com/datawhalechina/wonderful-sql/blob/main/ch03:%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) 47 | - :white_check_mark: [3.2 子查询](https://github.com/datawhalechina/wonderful-sql/blob/main/ch03:%E5%A4%8D%E6%9D%82%E4%B8%80%E7%82%B9%E7%9A%84%E6%9F%A5%E8%AF%A2.md#32-%E5%AD%90%E6%9F%A5%E8%AF%A2) 48 | - :white_check_mark: [3.3 各种各样的函数](https://github.com/datawhalechina/wonderful-sql/blob/main/ch03:%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) 49 | - :white_check_mark: [3.4 谓词](https://github.com/datawhalechina/wonderful-sql/blob/main/ch03:%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) 50 | - :white_check_mark: [3.5 CASE 表达式](https://github.com/datawhalechina/wonderful-sql/blob/main/ch03:%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) 51 | - :white_check_mark: [参考答案链接](https://xz9235vqyp.feishu.cn/docs/doccn4Ll8TU5b76SQ93uHlaHjEd) 52 | 53 | * ch04:集合运算 54 | - :white_check_mark: [4.1 表的加减法](https://github.com/datawhalechina/wonderful-sql/blob/main/ch04:%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) 55 | - :white_check_mark: [4.2 连结(JOIN)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch04:%E9%9B%86%E5%90%88%E8%BF%90%E7%AE%97.md#42-%E8%BF%9E%E7%BB%93join) 56 | - :white_check_mark: [参考答案链接](https://xz9235vqyp.feishu.cn/docs/doccnnBUWyb5NQZ27fVuTR2Tvie) 57 | 58 | * ch05:SQL高级处理 59 | - :white_check_mark: [5.1 窗口函数](https://github.com/datawhalechina/wonderful-sql/blob/main/ch05:SQL%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) 60 | - :white_check_mark: [5.2 窗口函数种类](https://github.com/datawhalechina/wonderful-sql/blob/main/ch05:SQL%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) 61 | - :white_check_mark: [5.3 窗口函数的的应用 - 计算移动平均](https://github.com/datawhalechina/wonderful-sql/blob/main/ch05:SQL%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) 62 | - :white_check_mark: [5.4 GROUPING运算符](https://github.com/datawhalechina/wonderful-sql/blob/main/ch05:SQL%E9%AB%98%E7%BA%A7%E5%A4%84%E7%90%86.md#54-grouping%E8%BF%90%E7%AE%97%E7%AC%A6) 63 | - :white_check_mark: [5.5 存储过程和函数](https://github.com/datawhalechina/wonderful-sql/blob/main/ch05:SQL%E9%AB%98%E7%BA%A7%E5%A4%84%E7%90%86.md#55-%E5%AD%98%E5%82%A8%E8%BF%87%E7%A8%8B%E5%92%8C%E5%87%BD%E6%95%B0) 64 | - :white_check_mark: [5.6 预处理声明 PREPARE Statement](https://github.com/datawhalechina/wonderful-sql/blob/main/ch05:SQL%E9%AB%98%E7%BA%A7%E5%A4%84%E7%90%86.md#56-%E9%A2%84%E5%A4%84%E7%90%86%E5%A3%B0%E6%98%8E-prepare-statement) 65 | - :white_check_mark: [参考答案链接](https://xz9235vqyp.feishu.cn/docs/doccn8YjyxIyV2aQ1J7mQdMHNrd) 66 | 67 | * ch06:决胜秋招 68 | 69 | - Section A 70 | 71 | - :white_check_mark: [练习一: 各部门工资最高的员工(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.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) 72 | - :white_check_mark: [练习二: 换座位(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.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) 73 | - :white_check_mark: [练习三: 分数排名(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.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) 74 | - :white_check_mark: [练习四:连续出现的数字(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.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) 75 | - :white_check_mark: [练习五:树节点 (难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.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) 76 | - :white_check_mark: [练习六:至少有五名直接下属的经理 (难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.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) 77 | - :white_check_mark: [练习七:查询回答率最高的问题 (难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%B8%83%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) 78 | - :white_check_mark: [练习八:各部门前3高工资的员工(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E5%85%AB%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) 79 | - :white_check_mark: [练习九:平面上最近距离 (难度: 困难)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%B9%9D%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) 80 | - :white_check_mark: [练习十:行程和用户(难度:困难)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E5%8D%81%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) 81 | 82 | - Section B 83 | 84 | - :white_check_mark: [练习一: 行转列(难度:中等))](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%B8%80%E8%A1%8C%E8%BD%AC%E5%88%97) 85 | - :white_check_mark: [练习二: 列转行(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%BA%8C%E5%88%97%E8%BD%AC%E8%A1%8C) 86 | - :white_check_mark: [练习三: 谁是明星带货主播?(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%B8%89%E5%B8%A6%E8%B4%A7%E4%B8%BB%E6%92%AD) 87 | - :white_check_mark: [练习四: MySQL 中如何查看sql语句的执行计划?可以看到哪些信息?(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E5%9B%9Bmysql-%E4%B8%AD%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8Bsql%E8%AF%AD%E5%8F%A5%E7%9A%84%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E5%93%AA%E4%BA%9B%E4%BF%A1%E6%81%AF) 88 | - :white_check_mark: [练习五: 解释一下 SQL 数据库中 ACID 是指什么?(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%BA%94%E8%A7%A3%E9%87%8A%E4%B8%80%E4%B8%8B-sql-%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD-acid-%E6%98%AF%E6%8C%87%E4%BB%80%E4%B9%88) 89 | 90 | 91 | - Section C 92 | 93 | - :white_check_mark: [练习一: 行转列(难度:中等)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%B8%80%E8%A1%8C%E8%BD%AC%E5%88%97-1) 94 | - :white_check_mark: [练习二: 列转行(难度:困难)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%BA%8C%E5%88%97%E8%BD%AC%E8%A1%8C-1) 95 | - :white_check_mark: [练习三: 连续登录(难度:困难)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%B8%89%E8%BF%9E%E7%BB%AD%E7%99%BB%E5%BD%95) 96 | - :white_check_mark: [练习四: 用户购买商品推荐(难度:困难)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E5%9B%9B%E7%94%A8%E6%88%B7%E8%B4%AD%E4%B9%B0%E5%95%86%E5%93%81%E6%8E%A8%E8%8D%90) 97 | - :white_check_mark: [练习五: hive 数据倾斜的产生原因及优化策略(难度:困难)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%B8%89%E8%BF%9E%E7%BB%AD%E7%99%BB%E5%BD%95) 98 | - :white_check_mark: [练习六: LEFT JOIN 是否可能会出现多出的行?为什么?](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E7%BB%83%E4%B9%A0%E4%BA%94left-join-%E6%98%AF%E5%90%A6%E5%8F%AF%E8%83%BD%E4%BC%9A%E5%87%BA%E7%8E%B0%E5%A4%9A%E5%87%BA%E7%9A%84%E8%A1%8C%E4%B8%BA%E4%BB%80%E4%B9%88) 99 | - :white_check_mark: [附加题: 写一写本次学习的收获。](https://github.com/datawhalechina/wonderful-sql/blob/main/ch06:%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B.md#%E5%86%99%E4%B8%80%E5%86%99%E6%9C%AC%E6%AC%A1%E5%AD%A6%E4%B9%A0%E7%9A%84%E6%94%B6%E8%8E%B7) 100 | 101 | - :white_check_mark: [参考答案链接](https://xz9235vqyp.feishu.cn/docs/doccnruf8gPtnAm9gbxKJRU0pZf) 102 | 103 | ## 常见问题 104 | 105 | - **在线教程页面无法打开**: 106 | 107 | 测试中存在部分人打不开在线教程的情况。 108 | 109 | 部分小伙伴反馈尝试切换浏览器后可以正常打开了,还可以参考 [提高国内访问 GitHub 的速度的 9 种方案](https://mp.weixin.qq.com/s/sHQ0yjqYNgEb1Bw_X0BxZg) 中介绍的方法尝试打开。 110 | 111 | 如果仍然不行,最有效的解决办法是科学上网。 112 | 113 | - **无法加载图片的解决办法**: 114 | 115 | 根本解决办法还是科学上网,也可以尝试修改host文件看下是否能解决。 116 | 117 | [windows解决方案:修改host文件](https://blog.csdn.net/u011583927/article/details/104384169) 118 | 119 | [备用链接:](https://gitee.com/datawhalechina/wonderful-sql) 120 | 121 | ## 致谢 122 | 123 | 感谢以下Datawhale成员对项目推进作出的贡献(排名不分先后): 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 |
内容贡献者名单
成员个人简介及贡献个人主页
王复振河北科技大学,公众号:数据科学探究,Datawhale成员,项目负责人,Task00/01/03/05/06内容构建 Github
杨煜数据分析师,公众号:BI数据可视化,Datawhale成员,Task05/06内容构建
闫钟峰图书馆员,Datawhale成员,Task00/04内容构建
杨梦迪上海大学硕士,Datawhale成员,Task02内容构建
苏鹏东北大学硕士,Datawhale成员,Task00/01/03内容构建Github
红星广东工业大学,Datawhale成员,内测小组成员
张晋北京理工大学,Datawhale成员,内测小组成员
汪健麟电子科技大学硕士,Datawhale成员,内测小组成员
177 | 178 | 179 | ## 关注我们 180 | 181 | > "Datawhale是一个专注AI领域的开源组织,以“for the learner,和学习者一起成长”为愿景,构建对学习者最有价值的开源学习社区。关注我们,一起学习成长。" 182 | 183 | 184 | -------------------------------------------------------------------------------- /ch00_环境搭建.md: -------------------------------------------------------------------------------- 1 | # 第0章:环境搭建 2 | 3 | ### 本章重点: 4 | * 在电脑上安装MySQL数据库系统 5 | * 安装客户端并连接到本机上的MySQL数据库 6 | * 使用提供的脚本创建本教程所使用的示例数据库 7 | 8 | ### 目录 9 | 10 | [1. MySQL 8.0 的安装](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%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) 11 | 12 | * [1.1 windows 下 MySQL 8.0 的下载安装](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#11-windows-%E4%B8%8B-mysql-80-%E7%9A%84%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85) 13 | - [1.1.1 下载](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#111-%E4%B8%8B%E8%BD%BD) 14 | - [1.1.2 安装](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#112-%E5%AE%89%E8%A3%85) 15 | 16 | * [1.2 macOS 下 MySQL 8.0 的下载安装](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#12-macos-%E4%B8%8B-mysql-80-%E7%9A%84%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85) 17 | - [1.1.1 下载](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#111-%E4%B8%8B%E8%BD%BD) 18 | 19 | * [1.3 Linux 下 MySQL 8.0 的下载安装](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#13-linux-%E4%B8%8B-mysql-80-%E7%9A%84%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85) 20 | - [1.3.1 CentOS MySQL 安装](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00%3A%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#131-centos-mysql-%E5%AE%89%E8%A3%85) 21 | - [1.3.2 Ubuntu MySQL 安装](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00%3A%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#132-ubuntu-mysql-%E5%AE%89%E8%A3%85) 22 | 23 | [2. 连接 MySQL 并执行 SQL 查询](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%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) 24 | 25 | * [2.0 使用命令行方式连接MySQL服务(推荐指数 ⭐ ⭐ ⭐)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#20-%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%96%B9%E5%BC%8F%E8%BF%9E%E6%8E%A5mysql%E6%9C%8D%E5%8A%A1%E6%8E%A8%E8%8D%90%E6%8C%87%E6%95%B0-star-star-star) 26 | * [2.1 [选学]使用 MySQL Workbench 连接 MySQL(推荐指数 ⭐)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#21-%E9%80%89%E5%AD%A6%E4%BD%BF%E7%94%A8-mysql-workbench-%E8%BF%9E%E6%8E%A5-mysql%E6%8E%A8%E8%8D%90%E6%8C%87%E6%95%B0-star) 27 | * [2.2 [选学]使用 HeidiSQL 连接 MySQL(推荐指数 ⭐ ⭐ ⭐)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#22-%E9%80%89%E5%AD%A6%E4%BD%BF%E7%94%A8-heidisql-%E8%BF%9E%E6%8E%A5-mysql%E6%8E%A8%E8%8D%90%E6%8C%87%E6%95%B0-star-star-star) 28 | * [2.3 [选学]使用 DBeaver 连接 MySQL(推荐指数 ⭐ ⭐ ⭐)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#23-%E9%80%89%E5%AD%A6%E4%BD%BF%E7%94%A8-dbeaver-%E8%BF%9E%E6%8E%A5-mysql%E6%8E%A8%E8%8D%90%E6%8C%87%E6%95%B0-star-star-star) 29 | * [2.4 [选学]使用 Navicat 连接 MySQL(推荐指数 ⭐ ⭐ ⭐ ⭐ ⭐)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#24-%E9%80%89%E5%AD%A6%E4%BD%BF%E7%94%A8-navicat-%E8%BF%9E%E6%8E%A5-mysql%E6%8E%A8%E8%8D%90%E6%8C%87%E6%95%B0-star-star-star-star-star) 30 | * [2.5 [选学]使用 SQLyog 连接 MySQL(推荐指数 ⭐ ⭐ ⭐ ⭐)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#25-%E9%80%89%E5%AD%A6%E4%BD%BF%E7%94%A8-sqlyog-%E8%BF%9E%E6%8E%A5-mysql%E6%8E%A8%E8%8D%90%E6%8C%87%E6%95%B0-star-star-star-star) 31 | * [2.6 [选学]DataGrip的安装和连接MySQL(推荐指数 ⭐ ⭐ ⭐ ⭐)](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#26-%E9%80%89%E5%AD%A6datagrip%E7%9A%84%E5%AE%89%E8%A3%85%E5%92%8C%E8%BF%9E%E6%8E%A5mysql%E6%8E%A8%E8%8D%90%E6%8C%87%E6%95%B0-star-star-star-star) 32 | 33 | [3. 创建学习用的数据库](https://github.com/datawhalechina/wonderful-sql/blob/main/ch00:%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA.md#3-%E5%88%9B%E5%BB%BA%E5%AD%A6%E4%B9%A0%E7%94%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93) 34 | 35 | ## 1. MySQL 8.0 的安装 36 | 37 | 考虑到大家所使用的操作系统的不同, 本教程分别提供了 windows 10, macOS和centos平台上的MySQL 8.0 的安装流程, 你可根据自己所使用电脑的操作系统选择以下三节中的一节进行学习和安装。 38 | 39 | ### 1.1 windows 下 MySQL 8.0 的下载安装 40 | 41 | 首先以最常见的 win10 为例, 介绍 MySQL8.0 的下载安装。 42 | 43 | #### 1.1.1 下载 44 | 45 | MySQL 针对个人用户和商业用户提供了不同的版本, MySQL 社区版(MySQL Community Edition) 是供个人用户免费下载的开源数据库, 本教程将以MySQL 社区版为例进行安装连接和SQL查询的讲解。 46 | 47 | 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/),然后在新页面里选择所需历史版本的社区版。 48 | 49 | 如果想下载本教程所使用的 MySQL 8.0.21.0, 也可以在百度⽹盘下载, 50 | 51 | 下载链接:[https://pan.baidu.com/s/1SOtMoVqqRXwa2qD0siHcIg](https://pan.baidu.com/s/1SOtMoVqqRXwa2qD0siHcIg)提取码:80lf 52 | 53 | 备用下载链接:[https://pan.baidu.com/s/1zK2vj50DvuAee-EqAcl-0A](https://pan.baidu.com/s/1zK2vj50DvuAee-EqAcl-0A)提取码:80lf 54 | 55 | 我们接下来以文档写作时的最新版 MySQL 8.0.21 为例, 进行下载安装的介绍。 56 | 57 | 进入到[MySQL Installer for Windows](https://dev.mysql.com/downloads/windows/)页面后, 选择下载下方的完整安装程序。 58 | 59 | ![图片](./img/ch00/ch0001.png) 60 | 61 | 在下载页面选择下方的不注册,仅下载。 62 | 63 | ![图片](./img/ch00/ch0002.png) 64 | 65 | 完成下载后, 得到一个后缀为msi的安装文件。 66 | 67 | ![图片](./img/ch00/ch0003.png) 68 | 69 | #### 1.1.2 安装 70 | 71 | 找到刚才下载好的msi文件, 双击开始安装. :exclamation::exclamation::exclamation:**强烈建议初学者采用完全安装模式( Full )进行安装**(缺点是不能修改安装目录): 72 | 73 | ![图片](./img/ch00/ch0004.png) 74 | 75 | 如果想修改安装路径,需要选择 `custom` 安装模式。包括安装路径和数据存放路径, 注意要安装组件至右侧,再进行点选, 之后点击 `Advanced Options` 按钮进行修改。 76 | 77 | ![图片](./img/ch00/ch0005-mysql-install-custom.png) 78 | 79 | ![图片](./img/ch00/ch0005-mysql-install-custom2.png) 80 | 81 | 安装过程中, 部分模块会依赖其他组件(每台电脑上列出的依赖项很可能会有不同)。 82 | 83 | ![图片](./img/ch00/ch0006.png) 84 | 85 | 如果你的电脑之前没有安装过这些组件, 则需要额外进行安装, 此处点击 Execute 按钮即可: 86 | 87 | ![图片](./img/ch00/ch0007.png) 88 | 89 | 在这些所依赖的组件的安装过程中, 只需要一路选择"同意"并逐个安装就可以了: 90 | 91 | ![图片](./img/ch00/ch0008.png) 92 | 93 | 安装好⼀个组件后, 点击关闭按钮, ⾃动开始安装下⼀个组件(这一步根据操作系统版本可能会略有不同) 94 | 95 | ![图片](./img/ch00/ch0009.png) 96 | 97 | ![图片](./img/ch00/ch0010.png) 98 | 99 | ![图片](./img/ch00/ch0011.png) 100 | 101 | 正常情况下,会将所有组件安装成功.但可能会有个别组件未安装成功. 个别组件没有呈现绿⾊是因为你的电脑中缺少某个程序, 例如, 如果你的电脑没有安装 Python 环境, 则该项目就不会呈现绿色. 待下边剩下 3 个按钮且上⽅⼤部分组件为绿色时, 即可点击 Next: 102 | 103 | ![图片](./img/ch00/ch0012.png) 104 | 105 | 如果有个别组件未安装成功, 此时可以先选择 Yes, 忽略个别组件的安装。 106 | 107 | ![图片](./img/ch00/ch0013.png) 108 | 109 | 点击 Excute, 开始安装服务器软件MySQL Server, 连接和查询软件MySQL Workbench及其他相关软件等内容。 110 | 111 | ![图片](./img/ch00/ch0014.png) 112 | 113 | 稍等片刻, 安装完成后, 点击 Next 114 | 115 | ![图片](./img/ch00/ch0015.png) 116 | 117 | ![图片](./img/ch00/ch0016.png) 118 | 119 | 下图这一步是选是否以集群方式安装 MySQL, 我们选择默认的第一个, 然后点击 Next: 120 | 121 | ![图片](./img/ch00/ch0017.png) 122 | 123 | 此处上边的各种相关配置保持默认即可, **勾选最下边的"Show Advanced and Logging Options"框,** 然后点击 Next: 124 | 125 | ![图片](./img/ch00/ch0018.png) 126 | 127 | 下图是密码强度的设置, 第⼀种模式为强密码校验模式, MySQL 8.0 推荐使⽤最新的数据库和客户端, 更换了加密插件, 这可能导致第三⽅客户端⼯具⽆法连接数据库。 128 | 129 | 第⼆种加密⽅式沿袭了 MySQL 5.x 的加密⽅式, 对第三⽅⼯具连接不敏感, 我们仅为了学习 SQL 查询, 并不需要很高的安全性, 因此此处请务必选择第二种⽅式(非常重要): 130 | 131 | ![图片](./img/ch00/ch0019.png) 132 | 133 | 在这一步设置 MySQL 的 root 账户密码, 由于上一步选择了第二个选项, 因此这里可以设置为较简单容易记忆的而密码, 例如"123456". 建议设置⽐较简单的密码, 并将密码记录下来以防遗忘, 忘记密码是⼀件麻烦事。 134 | 135 | ![图片](./img/ch00/ch0020.png) 136 | 137 | 此处保持默认即可, 如果 windows service name 右侧有⻩⾊警告图标显示, 表示名称重复, ⼿动更换⼀个名称即可, 然后点击 Next: 138 | 139 | ![图片](./img/ch00/ch0021.png) 140 | 141 | Logging Options 这里使用默认设置即可, 我们的学习中暂时用不到这些设置, 直接点击 Next: 142 | 143 | ![图片](./img/ch00/ch0022.png) 144 | 145 | 下图是设置是否大小写敏感的. 这一步非常重要,**由于windows系统是大小写不敏感的, 请大家务必使用第一个选项Lower Case**。 146 | 147 | ![图片](./img/ch00/ch0023.png) 148 | 149 | 点击 Execute 150 | 151 | ![图片](./img/ch00/ch0024.png) 152 | 153 | 完成安装后, 在下图中点击 Finish 回到安装的主进程: 154 | 155 | ![图片](./img/ch00/ch0025.png) 156 | 157 | 在主进程界面点击 Next 158 | 159 | ![图片](./img/ch00/ch0026.png) 160 | 161 | 这一步无需任何选择, 直接点击 Finish 162 | 163 | ![图片](./img/ch00/ch0027.png) 164 | 165 | 进入到 Connect To Server 界面后, 输⼊刚才设置的密码, 点击 check 进⾏校验, 校验通过后 Status 会显示连接成功, 然后点击 Next 166 | 167 | ![图片](./img/ch00/ch0028.png) 168 | 169 | 点击 Excute 应用设置: 170 | 171 | ![图片](./img/ch00/ch0029.png) 172 | 173 | 上述步骤完成后, 点击 Finish 174 | 175 | ![图片](./img/ch00/ch0030.png) 176 | 177 | 回到安装主进程后, 点击 Next 178 | 179 | ![图片](./img/ch00/ch0031.png) 180 | 181 | 点击 Finish,完成安装. 182 | 183 | ![图片](./img/ch00/ch0032.png) 184 | 185 | 现在, 你的电脑上就已经安装了MySQL的服务器软件、用于连接服务器进行查询的MySQL Workbench, 以及其他程序语言连接MySQL的驱动, 此外还安装了几个示例数据库, 但本教程将采用《SQL基础教程》一书中的示例数据库, 该数据库的创建和数据导入将在后续进行介绍。 186 | 187 | ### 1.2 macOS 下 MySQL 8.0 的下载安装 188 | 189 | 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/),然后在新页面里选择所需历史版本的社区版。 190 | 191 | ![图片](./img/ch00/ch0033.png) 192 | 193 | 然后选择下载dmg安装文件。 194 | 195 | ![图片](./img/ch00/ch0034.png) 196 | 197 | 点击下方的直接下载。 198 | 199 | ![图片](./img/ch00/ch0035.png) 200 | 201 | 下载的文件为: 202 | 203 | ![图片](./img/ch00/ch0036.png) 204 | 205 | 如果官网下载速度很慢, 或者希望下载本教程所使用的 MySQL 8.0.21.0, 也可以在百度⽹盘下载, 206 | 207 | 下载链接:[https://pan.baidu.com/s/1ka22UtzqFdOaIosrpKz92w](https://pan.baidu.com/s/1ka22UtzqFdOaIosrpKz92w) 提取码: 8xh4 208 | 209 | 备用下载链接:[https://pan.baidu.com/s/1XeA_8PQvvRePEdZ5ayOT-Q](https://pan.baidu.com/s/1XeA_8PQvvRePEdZ5ayOT-Q) 提取码:8xh4 210 | 211 | 我们接下来以文档写作时的最新版为 8.0.21 为例, 进行下载安装讲解。 212 | 213 | 在mac上直接双击dmg文件就可以开始安装了. 我们只选择了安装MySQL Community Server, 因此安装过程较为简单。 214 | 215 | ![图片](./img/ch00/ch0037.png) 216 | 217 | ![图片](./img/ch00/ch0038.png) 218 | 219 | ![图片](./img/ch00/ch0039.png) 220 | 221 | 注意, 在配置MySQL服务器这一步, 最好选择下边的选项, 这样就可以使用简单密码。 222 | 223 | ![图片](./img/ch00/ch0040.png) 224 | 225 | 在 Configuration 接下来的步骤需要设置密码, 如果上一步选择了第二个选项, 这里就可以使用比较简单的密码. 请务必牢记自己设置的密码。 226 | 227 | ![图片](./img/ch00/ch0041.png) 228 | 229 | 注意, 如果在前一步选择使用了MySQL8.0强密码, MySQL安装过程中会自动生成一个随机密码, 类似于下图这种形式: 230 | 231 | ![图片](./img/ch00/ch0042.png) 232 | 233 | 此时请截图保留该密码, 并在安装完成后, 使用该密码登录并重新设置密码. 由于选择使用了强密码, 此时设置密码必须使用大小写字母数字和特殊符号的组合。 234 | 235 | 完成安装后, 打开电脑的系统偏好设置, 会出现MySQL的服务标识。 236 | 237 | ![图片](./img/ch00/ch0043.png) 238 | 239 | 正确安装MySQL后, 打开上述截图中的MySQL之后会看到如下界面, 在这里可以启动和停止MySQL服务, 以及配置MySQL是否随电脑启动而自动启动。 240 | 241 | ![图片](./img/ch00/ch0044.png) 242 | 243 | 安装之后, 如果我们直接在终端输入mysql, 会提示找不到命令, 需要配置一下环境变量才可以, 输入以下命令: 244 | 245 | ```plain 246 | PATH="$PATH":/usr/local/mysql/bin 247 | ``` 248 | 再通过终端输入mysql登录命令后, 就可以看到mysql的交互式界面了。 249 | ![图片](./img/ch00/ch0045.png) 250 | 251 | 然后输入以下内容, 将自己电脑的mysql路径配置到环境变量中, 如果在安装过程中你没修改过安装路径, 那么你的电脑上MySQL的路径应该和下述代码中所使用的路径是一致的: 252 | 253 | ```plain 254 | export PATH=$PATH:/usr/local/mysql/bin 255 | ``` 256 | ![图片](./img/ch00/ch0046.png) 257 | 258 | 运行上述配置后, 通过输入下面这条命令使修改生效 259 | 260 | ```plain 261 | source ~/.bash_profile 262 | ``` 263 | 接下来, 在你的终端中输入命令来登录到MySQL 264 | ```plain 265 | mysql -u root -p 266 | ``` 267 | 然后需要输入你刚才设置的密码(如果你选择了强密码, 则这里需要输入你查到的随机密码), 如果看到以下界面, 则表示你的电脑上: 1.MySQL8.0已经正确安装, 2.已经正确配置了MySQL8.0的环境变量,并且3.已经启动MySQL服务器程序. 如果并没有出现下属界面, 请按照上述三个顺序逐个检查。 268 | 269 | ![图片](./img/ch00/ch0047.png) 270 | 271 | 使用终端(或者windows下的命令行)与MySQL进行交互是非常便捷和高效的, 但是对于平时不怎么使用终端的普通人来说, 使用终端在做数据查询时, 在查询结果的显示和导出方面有诸多不便, 特别是当我们对 SQL 查询不熟练的时候, 这种方式很不利于我们进行查询语句的调试. 因此本教程将选择查询界面更加友好的客户端工具来连接数据库, 这种通过终端连接MySQL的方式暂时不再使用。 272 | 273 | 接下来请安装跳转到2.1节安装MySQL Workbench并连接本机的MySQL服务。 274 | 275 | >注: 276 | >macOS上的SQL查询工具也有很多其他的选择, 比如DBeaver(开源, 免费), DataGrip(需付费购买,提供30天的免费试用期, 学生使用学校的邮箱可以申请到一年的免费使用权)等,可参考知乎上的问题 : 277 | >Mac平台上有哪些好的SQL 数据库开发工具?[https://www.zhihu.com/question/20498949](https://www.zhihu.com/question/20498949) 278 | 279 | ![图片](./img/ch00/ch0048.png) 280 | 281 | ### 1.3 Linux 下 MySQL 8.0 的下载安装 282 | 283 | #### 1.3.1 CentOS MySQL 安装 284 | 285 | 本节我们以 centos 版本的 Linux 操作系统为例, 介绍下载安装 MySQL8.0.21 的过程. 示例操作系统的linux 版本:centos-release-7-7.1908.0.el7.centos.x86_64 286 | 287 | 在 CentOS 系统中默认是安装了 MariaDB 的, 但是我们需要的是 MySQL, 我们可以直接下载安装 MySQL, 安装 MySQL 可以覆盖 MariaDB。 288 | 289 | >关于 MariaDB: 290 | >MariaDB 数据库管理系统是 MySQL 的一个分支, 主要由开源社区在维护, 采用 GPL 授权许可. 开发这个分支的原因之一是:甲骨文公司收购了 MySQL 后, 有将 MySQL 闭源的潜在风险, 因此社区采用分支的方式来避开这个风险. MariaDB 的目的是完全兼容 MySQL, 包括 API 和命令行, 使之能轻松成为 MySQL 的代替品. 但在两个分支经过了几年的各自迭代之后, 在一些方面二者出现了一些差异。 291 | 292 | ##### 1.3.1.1 安装步骤 293 | 294 | 首先, 从[MySQL官网](https://dev.mysql.com/downloads/repo/yum/)下载 MySQL 的 Yum Repository. 根据 CentOS 和 MySQL 的版本,选择下载相对应的文件。本文选择红色方框的文件。 295 | 296 | ![图片](./img/ch00/ch0049.png) 297 | 298 | Yum 是一个基于 rpm 的软件包管理器, 它可以从指定的服务器自动下载 RPM 包并且安装, 可以自动处理依赖性关系, 并且一次安装所有依赖的软体包, 无须繁琐地一次次下载、安装。 299 | 300 | 下载命令: 301 | 302 | ```plain 303 | wget https://dev.mysql.com/get/mysql80-community-release-el7-2.noarch.rpm 304 | ``` 305 | 用 yum 命令安装下载好的 rpm 包. 306 | ```plain 307 | yum -y install mysql80-community-release-el7-2.noarch.rpm 308 | ``` 309 | 安装 MySQL 服务器. 310 | ```plain 311 | yum -y install mysql-community-server 312 | ``` 313 | 这一步由于要下载安装文件, 可能会花一些时间. 安装完成后就会覆盖掉之前的 mariadb。 314 | 当出现如下图所示的内容,则代表 MySQL 就安装完成了。 315 | 316 | ![图片](./img/ch00/ch0050.png) 317 | 318 | ##### 1.3.1.2 初始配置 319 | 320 | 启动 MySQL 321 | 322 | ```plain 323 | systemctl start mysqld.service 324 | ``` 325 | 查看 MySQL 运行状态, Active 后面的状态代表启功服务后为 active (running), 停止后为 inactive (dead), 运行状态如图: 326 | ```plain 327 | systemctl status mysqld.service 328 | ``` 329 | ![图片](./img/ch00/ch0051.png) 330 | 331 | 重新启动 Mysql 和停止 Mysql 的命令如下: 332 | 333 | ```plain 334 | service mysqld restart #重新启动 Mysql 335 | systemctl stop mysqld.service #停止 Mysql 336 | ``` 337 | 此时 MySQL 已经开始正常运行, 不过要想进入 MySQL 还得先找出此时 root 用户的密码, 通过如下命令可以在日志文件中找出密码: 338 | 为了加强安全性, MySQL8.0 为 root 用户随机生成了一个密码, 在 error log 中, 关于 error log 的位置, 如果安装的是 RPM 包, 则默认是/var/log/mysqld.log.  只有启动过一次 mysql 才可以查看临时密码 339 | 340 | 使用命令: 341 | 342 | ```plain 343 | grep 'temporary password' /var/log/mysqld.log 344 | ``` 345 | 查看初始的随机密码: 346 | ![图片](./img/ch00/ch0052.png) 347 | 348 | 登录 root 用户 349 | 350 | ```plain 351 | mysql -u root -p 352 | ``` 353 | 然后输入上述查到的初始密码. 登录后还不能做任何查询或建库操作, 因为 MySQL 默认必须修改初始的随机密码之后才能操作数据库,否则会报错: 354 | 355 | ![图片](./img/ch00/ch0053.png) 356 | 357 | 修改密码为"123456", 注意结尾要有分号, 表示语句的结束。 358 | 359 | ```plain 360 | ALTER USER 'root'@'localhost' IDENTIFIED BY '123456'; 361 | ``` 362 | 这里有个问题, 新密码设置的时候如果设置的过于简单会报错: 363 | 364 | ![图片](./img/ch00/ch0054.png) 365 | 366 | 原因是因为 MySQL 有密码设置的规范, 具体是与 validate_password_policy 的值有关: 367 | 368 | ![图片](./img/ch00/ch00541.png) 369 | 370 | MySQL 完整的初始密码规则可以通过如下命令查看: 371 | 372 | ![图片](./img/ch00/ch0055.png) 373 | 374 | 密码的长度是由 validate_password_length 决定的, 而 validate_password_length 的计算公式是: 375 | 376 | ```plain 377 | validate_password_length = validate_password_number_count + validate_password_special_char_count + (2 * validate_password_mixed_case_count) 378 | ``` 379 | 如果想要设置简单的密码必须要修改约束, 修改两个全局参数: 380 | * **validate_password_policy**代表密码策略, 默认是 1:符合长度, 且必须含有数字, 小写或大写字母, 特殊字符. 设置为 0 判断密码的标准就基于密码的长度了. 一定要先修改两个参数再修改密码 381 | ```plain 382 | mysql> set global validate_password.policy=0; 383 | ``` 384 | * **validate_password_length**代表密码长度, 最小值为 4 385 | ```plain 386 | mysql> set global validate_password.length=4; 387 | ``` 388 | 修改完,如图 389 | 390 | ![图片](./img/ch00/ch0056.png) 391 | 392 | 此时密码就可以设置的很简单, 例如 1234 之类的. 到此数据库的密码设置就完成了。 393 | 394 | 但此时还有一个问题, 就是因为安装了 Yum Repository, 以后每次 yum 操作都会自动更新, 如不需要更新, 可以把这个 yum 卸载掉: 395 | 396 | ```plain 397 | [root@localhost ~]# yum -y remove mysql80-community-release-el7-2.noarch 398 | ``` 399 | 400 | 在 CentOS 中 MySQL 的主要配置所在的目录: 401 | 402 | ```plain 403 | 1 /etc/my.cnf 这是 mysql 的主配置文件 404 | 2 /var/lib/mysql mysql 数据库的数据库文件存放位置 405 | 3 /var/log mysql 数据库的日志输出存放位置 406 | ``` 407 | 一些可能会用到的设置: 408 | 409 | 设置表名为大小写不敏感: 410 | 411 | 1.用root帐号登录后, 使用命令 412 | 413 | ```plain 414 | systemctl stop mysqld.service 415 | ``` 416 | 停止MySQL数据库服务,修改vi /etc/my.cnf,在[mysqld]下面添加 417 | ```plain 418 | lower_case_table_names=1 419 | ``` 420 | 这里的参数 0 表示区分大小写,1 表示不区分大小写. 421 | 2.做好数据备份,然后使用下述命令删除数据库数据(删除后, 数据库将恢复到刚安装的状态) 422 | 423 | ```plain 424 | rm -rf /var/lib/mysql 425 | ``` 426 | 3.重启数据库 ,此时数据库恢复到初始状态。 427 | ```plain 428 | service mysql start 429 | ``` 430 | 4.重复安装时的操作, 查找临时密码 431 | ```plain 432 | grep 'temporary password' /var/log/mysqld.log 433 | ``` 434 | 5.修改密码. 密码8位以上, 大小写符号数据. 如想要使用简单密码, 需按照上述安装流程中的步骤进行操作。 435 | ```plain 436 | ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '****';update user set host = "%" where user='root'; 437 | ``` 438 | 6.刷新MySQL的系统权限相关表 439 | ```plain 440 | FLUSH PRIVILEGES; 441 | ``` 442 | 此时, MySQL的表名的大小写不再敏感。 443 | 444 | ##### 1.3.1.3 配置远程访问 445 | 446 | 如果你想要在另外一台电脑上连接 centos 上安装的 MySQL, 那么还需要一些其他的设置。 447 | 448 | 首先需要将 MySQL 设置为可以远程连接,设置 mysql 库的 user 表中帐号的 host 为%, %表示可以从任意 ip 连接 mysql, 为了安全性, 也可以设置为你自己所用于连接 centos 上 MySQL 的电脑所使用的 IP。 449 | 450 | 其次, MYSQL 8.0 内新增加 mysql_native_password 函数,通过更改这个函数密码来进行远程连接。 451 | 452 | 例如,更改 root 用户的 native_password 密码 453 | 454 | ```plain 455 | ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY'MyPass@123'; 456 | ``` 457 | 接下来为 centos 的防火墙开启 MySQL 所使用的 3306 端口,并重新加载防火墙: 458 | ```plain 459 | firewall-cmd --zone=public --add-port=3306/tcp --permanent 460 | firewall-cmd --reload 461 | ``` 462 | 完成上述设置后, 重新启动 MySQL 服务: 463 | ```plain 464 | service mysqld restart #重新启动 Mysql 465 | ``` 466 | 最后, 在另外一台电脑上, 使用下一节介绍的各类客户端工具进行连接测试。 467 | 468 | #### 1.3.2 Ubuntu MySQL 安装 469 | 470 | [参考网址[(https://blog.csdn.net/DXRfighting/article/details/119754581) 471 | 472 | ##### 1.3.2.1 安装步骤 473 | 474 | 安装 MySQL Server 475 | 476 | ```sh 477 | sudo apt-get install mysql-server 478 | ``` 479 | ![图片](./img/ch00/ubuntu-mysql-1.png) 480 | 481 | 482 | 安装 MySQL Server 483 | 484 | ```sh 485 | apt-get isntall mysql-client 486 | ``` 487 | ![图片](./img/ch00/ubuntu-mysql-2.png) 488 | 489 | 490 | 安装 libmysqlclient-dev 491 | ```sh 492 | sudo apt-get install libmysqlclient-dev 493 | ``` 494 | ![图片](./img/ch00/ubuntu-mysql-3.png) 495 | 496 | 497 | 查看 MySQL 运行状态 498 | 499 | 安装好之后使用sudo netstat -tap | grep mysql来查看mysql运行状态,如果处于listen状态,那就没问题。 500 | ![图片](./img/ch00/ubuntu-mysql-4.png) 501 | 502 | ##### 1.3.2.2 初始配置 503 | 504 | 接下来进行mysql初始配置,按照提示一个个的选择就好了。 505 | ```sh 506 | sudo mysql_secure_installation 507 | ``` 508 | ![图片](./img/ch00/ubuntu-mysql-5.png) 509 | 510 | ![图片](./img/ch00/ubuntu-mysql-6.png) 511 | 512 | 现在我们配置好了密码,查看一下 MySQL 状态 513 | ```sh 514 | systemctl status mysql.service 515 | ``` 516 | ![图片](./img/ch00/ubuntu-mysql-7.png) 517 | 518 | 显示如上说明正常。 519 | ##### 1.3.2.3 配置远程访问 520 | 521 | 下面配置远程访问。 522 | 打开配置文件 `mysqld.cnf` 523 | 524 | ```sh 525 | sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf 526 | ``` 527 | ![图片](./img/ch00/ubuntu-mysql-8.png) 528 | 529 | 将 `bind-address = 127.0.0.1` 注释掉(即在行首加#)。 530 | 531 | 然后登入Mysql,切换至 MySQL 数据库 532 | 533 | ![图片](./img/ch00/ubuntu-mysql-9.png) 534 | 535 | 使用如下命令删除匿名用户: 536 | 537 | ```sql 538 | delete from user where user=''; 539 | ``` 540 | 541 | ![图片](./img/ch00/ubuntu-mysql-a.png) 542 | 543 | 增加允许远程访问的用户或者允许现有用户的远程访问。删除匿名用户后,给root授予在任意主机(%)访问任意数据库的所有权限 544 | ```sql 545 | grant all privileges on *.* to 'root'@'%' identified by '123456' with grant option; 546 | ``` 547 | 548 | ![图片](./img/ch00/ubuntu-mysql-b.png) 549 | 550 | 如果需要指定访问主机,可以把%替换为主机的IP或者主机名。另外,这种方法会在数据库mysql的表user中,增加一条记录。如果不想增加记录,只是想把某个已存在的用户(例如root)修改成允许远程主机访问,则可以使用如下SQL来完成: 551 | ```sql 552 | update user set host='%' where user='root' and host='localhost'; 553 | ``` 554 | 最后退出重新启动 MySQL 555 | ```sh 556 | sudo service mysql restart 557 | ``` 558 | 559 | 560 | ## 2. 连接 MySQL 并执行 SQL 查询 561 | 562 | 在安装成功MySQL后, 我们可以通过开始菜单->控制面板->管理工具->服务中查找并开启或关闭MySQL服务. 开启服务后, MySQL Server将以后台服务的形式在你的电脑上运行. 如果想要进行查询, 还需要使用命令行工具或者其他更加友好的应用程序连接到MySQL服务。 563 | 564 | ### 2.0 使用命令行方式连接MySQL服务(推荐指数 :star: :star: :star:) 565 | 566 | 连接数据库的最基本的⽅式, 是使用命令⾏. 以win10为例, 在完成 MySQL 服务的安装后, 在开始菜单找到刚才安装好的 MySQL 8.0 命令⾏⼯具,单击即可打开: 567 | 568 | ![图片](./img/ch00/ch0057.png) 569 | 570 | 输⼊你在安装过程中为root用户设置的密码即可连接到数据库, 看到如下界⾯, 表示数据库安装成功,并且你已经使用命令行连接到了数据库(图中红框表示数据库版本), 在最后的 "mysql>" 后即可输入SQL命令执行各种数据库操作。 571 | 572 | ![图片](./img/ch00/ch0058.png) 573 | 574 | 但是使用命令行在做数据查询时, 在查询结果的显示和导出方面有诸多不便, 特别是当我们对 SQL 查询不熟练的时候, 这种方式不利于我们进行查询语句的修改和调试. 因此本教程将选择查询界面更加友好的客户端工具(使用MySQL Workbench)来连接数据库, 这种通过命令行连接的方式暂时不再使用。 575 | 576 | >常见的可用于连接MySQL数据库并进行查询等操作的管理工具包括开源软件 MySQL Workbench, HeidiSQL和DBeaver, 以及商业软件Navicat(有免费版和14天试用版),SQLyog(有免费的社区版)和DataGrip等等。 577 | 578 | ### 2.1 [选学]使用 MySQL Workbench 连接 MySQL(极不推荐 :exclamation::exclamation::exclamation:) 579 | 580 | MySQL Workbench 是 MySQL 官方的客户端工具, 支持windows, macOS和Linux. 对于windows用户, 我们在安装 MySQL 的时候由于选择的是完整安装模式, 因此也同时安装了这个工具, 对于macOS的用户, 可以在[https://dev.mysql.com/downloads/workbench/](https://dev.mysql.com/downloads/workbench/)选择macOS版本进行下载安装. MySQL Workbench 是一款功能强大的数据库管理工具, 它既可以用于设计数据库, 也可以用于连接数据库进行查询, 我们这个课程主要使用它的连接数据库进行查询的功能。 581 | 582 | 虽然是官方提供的客户端工具,但是使用过程中很容易出现莫名其妙的报错,建议选取其他类型的客户端。 583 | 584 | 如果你使用的是windows 7 操作系统, 打开 MySQL Workbench 后, 会有如下提示: 585 | 586 | ![图片](./img/ch00/ch0059.png) 587 | 588 | 这是说 MySQL 不再维护win7系统下的MySQL Workbench, 但并不影响使用. 打开MySQL Workbench后, 使用快捷键 ctrl+u,或者点击菜单栏里的 Database->Connect to Database, 进入数据库连接的设置界面, 如下图所示: 589 | 590 | ![图片](./img/ch00/ch0060.png) 591 | 592 | 然后如下图红框中设置连接本机的 MySQL8.0, 输入密码并点击 OK: 593 | 594 | ![图片](./img/ch00/ch0061.png) 595 | 596 | 如果弹出如下对话框,表示 MySQL 服务器设置为对于表名和列名的大小写敏感, 但由于 windows 系统默认的是大小写不敏感, 因此当表名或列名有大写字母时, 即使写的 SELECT 语句中正确地使用了大写的表名, 程序也无法正确执行. 这时候建议大家在开始学习查询之前,把表名逐一更改为小写。 597 | 598 | ![图片](./img/ch00/ch0062.png) 599 | 600 | 打开后的界⾯ 601 | 602 | ![图片](./img/ch00/ch0063.png) 603 | 604 | 在中间的编辑器里, 就可以写 SQL 查询了。 605 | 606 | 下一次打开软件时, 可以直接点击保存的数据库连接, 不需要先进行设置后再连接了: 607 | 608 | ![图片](./img/ch00/ch0064.png) 609 | 610 | ### 2.2 [选学]使用 HeidiSQL 连接 MySQL(推荐指数 :star: :star: :star:) 611 | 612 | HeidiSQL 是一款功能非常强大的开源免费的数据库客户端软件, 采用 Delphi 语言开发, 支持 Windows 操作系统. 支持 MySQL、Postgresql、MariaDB、Percona Server 和微软的 SQL Server, 官网下载地址:[https://www.heidisql.com/download.php](https://www.heidisql.com/download.php), 下载 portable 版本后, 解压缩就可以使用。 613 | 614 | ![图片](./img/ch00/ch0065.png) 615 | 616 | 点击文件夹中的 heidisql.exe, 在弹出对话框里点击"新建", 然后填写密码, 再点击"打开"即可连接到本机上安装的 MySQL 数据库。 617 | 618 | ![图片](./img/ch00/ch0066.png) 619 | 620 | 软件的主界面如图所示: 621 | 622 | ![图片](./img/ch00/ch0067.png) 623 | 624 | ### 2.3 [选学]使用 DBeaver 连接 MySQL(推荐指数 :star: :star: :star:) 625 | 626 | DBeaver 是一款基于 Java 开发的 **免费和开源(GPL)** 的通用数据库管理工具和 SQL 客户端, 提供 Windows, macOS和Linux全平台支持, 能够连接包括 `MySQL, PostgreSQL, Oracle, DB2, SQL Server, Sybase, Mimer, HSQLDB, Derby` 等主流数据库软件在内的绝大多数兼容 JDBC 驱动的数据库。DBeaver 提供一个图形界面用来查看数据库结构、执行 SQL 查询和脚本, 浏览和导出数据, 处理 BLOB/CLOB 数据, 修改数据库结构等等。 627 | 628 | 由于是开源软件, 大家可直接从官网([https://dbeaver.io/](https://dbeaver.io/))下载, 安装完成后, 打开软件, 点击"文件"菜单下的"新建连接"图标, 并选择 MySQL: 629 | 630 | ![图片](./img/ch00/ch0068.png) 631 | 632 | 然后点击下一步: 633 | 634 | ![图片](./img/ch00/ch0069.png) 635 | 636 | 在下方弹出的设置窗口中, "服务器地址"使用默认的localhost, "数据库"暂时留空, 然后在下方填入自己设置的密码, 最后点击测试连接。 637 | 638 | ![图片](./img/ch00/ch0070.png) 639 | 640 | 本次学习主要使用一个新建的 shop 数据库, 但因为相关数据我们还没导入(建库建表及数据导入的脚本在本章第三节),因此数据库这里先留空. 等下一步导入数据后, 再进一步修改连接参数。 641 | 642 | 首次连接时会提示需要下载驱动程序 643 | 644 | ![图片](./img/ch00/ch0071.png) 645 | 646 | 完成驱动程序的下载后, 如果弹出如下对话框, 则表示连接成功: 647 | 648 | ![图片](./img/ch00/ch0072.png) 649 | 650 | 点击确定并保存连接后, 以后就可以直接双击这个连接进行数据库连接了. 如果需要保存多个数据库连接, 可以使用快捷键 F2 或选中当前连接并点击鼠标右键后选择"重命名"为当前连接起一个便于识别的名称。 651 | 652 | ![图片](./img/ch00/ch0073.png) 653 | 654 | 接下来就可以开始写你的第一个 SQL 语句了: 如上图这样,选中刚刚保存的连接, 鼠标右键选第一个按钮"SQL 编辑器", 或者直接使用快捷键 F3, 就会打开一个 SQL 编辑器, 然后就可以在这里编写 SQL 语句了。 655 | 656 | 例如我们可以使用如下语句完成本教程所使用的示例数据库的创建: 657 | 658 | ![图片](./img/ch00/ch0074.png) 659 | 660 | 注意, 在使用创建数据库的语句时, 是无需在红框中选中数据库的, 但其他所有的创建表,导入数据, 和最常用的查询语句, 都需要选中相应的数据库. 在执行上述语句后, 我们可以回到连接设置里, 把默认数据库连接改为刚才创建的 shop。 661 | 662 | ![图片](./img/ch00/ch0075.png) 663 | 664 | ### 2.4 [选学]使用 Navicat 连接 MySQL(推荐指数 :star: :star: :star: :star: :star:) 665 | 666 | Navicat 包含了一系列的功能强大的数据库管理软件, 主要有: 完整功能版的 Navicat Premium, 以及专门用于MySQL数据库管理的 Navicat for MySQL, 用于PostgreSQL数据库管理的 Navicat forPostgreSQL, 用于SQL Server数据库管理的 Navicat for SQL Server, 用于Oracle数据库管理的 Navicat for Oracle, 等等, 但它提供的免费的版本 Navicat Lite 已足够本次课程使用。 667 | 668 | >注: 669 | >Navicat 官网已经不再提供 Navicat Lite 的下载了, 但可以通过搜索引擎找到 Navicat Lite 的历史版本的下载链接. 此外, 也可以从 Navicat 官网下载 Navicat Premium 或 Navicat for MySQL 的14天试用版。 670 | 671 | 链接:https://pan.baidu.com/s/1xdAEXkATNfIS_yhYNROlAQ 672 | 673 | 提取码:vktl 674 | 675 | ### 2.5 [选学]使用 SQLyog 连接 MySQL(推荐指数 :star: :star: :star: :star:) 676 | 677 | SQLyog 是业界著名的 Webyog 公司出品的一款简洁高效、功能强大的图形化 MySQL 数据库管理工具. SQLyog 的企业版是收费软件, 但该软件也提供了社区版供大家使用, 虽然在功能上有些限制, 但对于本课程已经足够用了。SQLyog 社区版的下载地址为[https://github.com/webyog/sqlyog-community/wiki/Downloads](https://github.com/webyog/sqlyog-community/wiki/Downloads) 678 | 679 | ### 2.6 [选学]DataGrip的安装和连接MySQL(推荐指数 :star: :star: :star: :star:) 680 | 681 | DataGrip是大名鼎鼎的 JetBrains 出品的数据库工具, 支持windows, macOS和Linux操作系统。 682 | 683 | ## 3. 创建学习用的数据库 684 | 685 | 根据《SQL基础教程》提供的MySQL版本的数据库,数据表的创建以及数据导入的代码, 经过一些修改, 创建了一份 sql 脚本, 运行该脚本可以一步到位地创建本文档所需的数据库shop及其中所有的表,并插入本教程所需要的所有数据。 686 | 687 | 下述SQL脚本可用于创建本教程所使用的示例数据库 `shop` 以及数据库中表的创建和数据的插入。 688 | 689 | 详见 [https://github.com/datawhalechina/wonderful-sql/blob/main/materials/create_table_sql/shop.sql](https://github.com/datawhalechina/wonderful-sql/blob/main/materials/create_table_sql/shop.sql) 690 | 691 | 不同客户端的 SQL 脚本导入方法有所不同,[navicat 导入 SQL 文件参考地址](https://blog.csdn.net/yangjiacho/article/details/122503793) 。导入后看不到数据库表的话,请尝试刷新数据库,一般刷新后就可以看到导入的表了。 692 | 693 | >SQL 脚本的一些要点-- v 2020-09-08 694 | >>1. 存储引擎使用 InnoDB, 字符集改为 utf8mb4 以更好地支持中文。 695 | >> 696 | >>2. 所有表名所使用的英文字母都改为小写(后续章节中,SQL 查询中的表名也需要相应修改为小写) 697 | >> 698 | >>3. 所有列名所使用的英文字母确认为小写(后续章节中,SQL 查询中的列名也需要相应修改为小写) 699 | >> 700 | >* MySQL Workbench 已测试通过(在win10 使用 MySQL Workbench 8.0.21) 701 | >* DBeaver 已测试通过(使用"执行 SQL 脚本(CTR+x)") (在win10 使用 DBeaver7.2.0) 702 | >* HeidiSQL 已测试通过(在win10 使用HeidiSQL 11.0.0) 703 | >* navicat 已测试通过(在win10&win7 使用 navicat premium 15.0.17) 704 | >* sqlyog 已测试通过(在win10 使用 SQLyog 12.09) 705 | >* 命令行 win10 下测试未通过. 插入中文数据时提示" Data too long for column 'product_name' at row 1",建议使用客户端进行数据库的创建和数据导入。 706 | -------------------------------------------------------------------------------- /ch01_初识数据库.md: -------------------------------------------------------------------------------- 1 | # 第一章:初识数据库 2 | 3 | 本章主要讲解数据库安装和数据库基本介绍,考虑易用性及普及度,本课程采取mysql进行教学。 4 | 5 | ## 1.1 初识数据库 6 | 7 | 数据库是将大量数据保存起来,通过计算机加工而成的可以进行高效访问的数据集合。该数据集合称为数据库(Database,DB)。用来管理数据库的计算机系统称为数据库管理系统(Database Management System,DBMS)。 8 | 9 | ### 1.1.1 DBMS的种类 10 | 11 | DBMS 主要通过数据的保存格式(数据库的种类)来进行分类,现阶段主要有以下 5 种类型. 12 | 13 | - 层次数据库(Hierarchical Database,HDB) 14 | 15 | - 关系数据库(Relational Database,RDB) 16 | 17 | - Oracle Database:甲骨文公司的RDBMS 18 | - SQL Server:微软公司的RDBMS 19 | - DB2:IBM公司的RDBMS 20 | - PostgreSQL:开源的RDBMS 21 | - MySQL:开源的RDBMS 22 | 23 | 如上是5种具有代表性的RDBMS,其特点是由行和列组成的二维表来管理数据,这种类型的 DBMS 称为关系数据库管理系统(Relational Database Management System,RDBMS)。 24 | 25 | - 面向对象数据库(Object Oriented Database,OODB) 26 | 27 | - XML数据库(XML Database,XMLDB) 28 | 29 | - 键值存储系统(Key-Value Store,KVS),举例:MongoDB 30 | 31 | 本课程将向大家介绍使用 SQL 语言的数据库管理系统,也就是关系数据库管理系统(RDBMS)的操作方法。 32 | 33 | ### 1.1.2 RDBMS的常见系统结构 34 | 35 | 使用 RDBMS 时,最常见的系统结构就是客户端 / 服务器类型(C/S类型)这种结构(图 1-3) 36 | 37 | ![图片](./img/ch01/ch01.01%E7%B3%BB%E7%BB%9F%E7%BB%93%E6%9E%84.jpg) 38 | 39 | ## 1.2 初识 SQL 40 | 41 | ![图片](./img/ch01/ch01.02%E8%A1%A8%E7%9A%84%E7%A4%BA%E4%BE%8B.jpg) 42 | 43 | 数据库中存储的表结构类似于excel中的行和列,在数据库中,行称为**记录**,它相当于一条记录,列称为**字段**,它代表了表中存储的数据项目。 44 | 45 | 行和列交汇的地方称为单元格,一个单元格中只能输入一条记录。 46 | 47 | SQL是为操作数据库而开发的语言。国际标准化组织(ISO)为 SQL 制定了相应的标准,以此为基准的SQL 称为标准 SQL。 48 | 49 | 完全基于标准 SQL 的 RDBMS 很少,通常需要根据不同的 RDBMS 来编写特定的 SQL 语句,原则上,本课程介绍的是标准 SQL 的书写方式。 50 | 51 | 根据对 RDBMS 赋予的指令种类的不同,SQL 语句可以分为以下三类. 52 | 53 | - **DDL** :DDL(Data Definition Language,数据定义语言) 用来创建或者删除存储数据用的数据库以及数据库中的表等对象。DDL 包含以下几种指令。 54 | 55 | - CREATE : 创建数据库和表等对象 56 | - DROP : 删除数据库和表等对象 57 | - ALTER : 修改数据库和表等对象的结构 58 | 59 | - **DML** :DML(Data Manipulation Language,数据操纵语言) 用来查询或者变更表中的记录。DML 包含以下几种指令。 60 | 61 | - SELECT :查询表中的数据 62 | - INSERT :向表中插入新数据 63 | - UPDATE :更新表中的数据 64 | - DELETE :删除表中的数据 65 | 66 | - **DCL** :DCL(Data Control Language,数据控制语言) 用来确认或者取消对数据库中的数据进行的变更。除此之外,还可以对 RDBMS 的用户是否有权限操作数据库中的对象(数据库表等)进行设定。DCL 包含以下几种指令。 67 | 68 | - COMMIT : 确认对数据库中的数据进行的变更 69 | - ROLLBACK : 取消对数据库中的数据进行的变更 70 | - GRANT : 赋予用户操作权限 71 | - REVOKE : 取消用户的操作权限 72 | 73 | 实际使用的 SQL 语句当中有 90% 属于 DML,本书同样会以 DML 为中心进行讲解。 74 | 75 | ### 1.2.1 SQL的基本书写规则 76 | 77 | * SQL语句要以分号( ; )结尾 78 | * SQL 不区分关键字的大小写,但是插入到表中的数据是区分大小写的 79 | * win 系统默认不区分表名及字段名的大小写 80 | * linux / mac 默认严格区分表名及字段名的大小写 81 | * 本教程已统一调整表名及字段名的为小写,以方便初学者学习使用。 82 | * 常数的书写方式是固定的 83 | 84 | 'abc', 1234, '26 Jan 2010', '10/01/26', '2010-01-26'...... 85 | 86 | * 单词需要用半角空格或者换行来分隔 87 | 88 | SQL 语句的单词之间需使用半角空格或换行符来进行分隔,且不能使用全角空格作为单词的分隔符,否则会发生错误,出现无法预期的结果。 89 | 90 | 请大家认真查阅 `./materials/附录1 - SQL 语法规范` ,养成规范的书写习惯。 91 | 92 | 93 | 94 | ### 1.2.2 数据库的创建及选择 95 | 96 | 语法: 97 | 98 | ```sql 99 | CREATE DATABASE < 数据库名称 > ; 100 | ``` 101 | 创建本课程使用的数据库 102 | ```sql 103 | CREATE DATABASE shop; 104 | ``` 105 | 执行 `SHOW DATABASES` 可以查询到所有的数据库,可以看到自己创建的数据库 `shop`。 106 | 107 | 在创建表之前,首先需要选定数据库,就是说你要在哪个数据库里创建表,语法是 `USE DATABASE_NAME`。 108 | 109 | 咱们这里就选择刚刚创建的 `shop` 数据库: 110 | 111 | ```sql 112 | USE shop; 113 | ``` 114 | ### 1.2.3 表的创建( CREATE TABLE 语句) 115 | 116 | 语法: 117 | 118 | ```sql 119 | CREATE TABLE < 表名 > 120 | ( < 列名 1> < 数据类型 > < 该列所需约束 > < 默认设置 > , 121 |   < 列名 2> < 数据类型 > < 该列所需约束 > < 默认设置 > , 122 |   < 列名 3> < 数据类型 > < 该列所需约束 > < 默认设置 > , 123 |   < 列名 4> < 数据类型 > < 该列所需约束 > < 默认设置 > , 124 |   . 125 |   . 126 |   . 127 |   < 该表的约束 1> , < 该表的约束 2> ,……); 128 | ``` 129 | 创建本课程用到的商品表 130 | 131 | ```sql 132 | CREATE TABLE product 133 | (product_id CHAR(4) NOT NULL, 134 |  product_name VARCHAR(100) NOT NULL, 135 |  product_type VARCHAR(32) NOT NULL DEFAULT "水果", 136 |  sale_price INTEGER , 137 |  purchase_price INTEGER , 138 |  regist_date DATE , 139 |  PRIMARY KEY (product_id)); 140 | ``` 141 | 142 | 执行 `SHOW TABLES` 可以查询到所有的表,可以看到自己创建的数据库 `product`。 143 | 144 | ### 1.2.4 命名规则 145 | 146 | * 只能使用半角英文字母、数字、下划线(_)作为数据库、表和列的名称 147 | * 名称必须以半角英文字母开头 148 | 149 | 表1-3 商品表和 product 表列名的对应关系 150 | 151 | ![图片](./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) 152 | 153 | ### 1.2.5 数据类型的指定 154 | 155 | 数据库创建的表,所有的列都必须指定数据类型,每一列都不能存储与该列数据类型不符的数据。 156 | 157 | 四种最基本的数据类型 158 | 159 | * INTEGER 型 160 | 161 | 用来指定存储整数的列的数据类型(数字型),不能存储小数。 162 | 163 | 164 | 165 | * CHAR 型 166 | 167 | 用来存储定长字符串,当列中存储的字符串长度达不到最大长度的时候,使用半角空格进行补足,由于会浪费存储空间,所以一般不使用。 168 | 169 | * VARCHAR 型 170 | 171 | 用来存储可变长度字符串,定长字符串在字符数未达到最大长度时会用半角空格补足,但可变长字符串不同,即使字符数未达到最大长度,也不会用半角空格补足。 172 | 173 | * DATE 型 174 | 175 | 用来指定存储日期(年月日)的列的数据类型(日期型)。 176 | 177 | ### 1.2.6 约束的设置 178 | 179 | 约束是除了数据类型之外,对列中存储的数据进行限制或者追加条件的功能。 180 | 181 | `NOT NULL`是非空约束,即该列必须输入数据。 182 | 183 | `PRIMARY KEY`是主键约束,代表该列是唯一值,可以通过该列取出特定的行的数据。 184 | 185 | ### 1.2.7 表的删除和更新 186 | 187 | * 删除表的语法: 188 | ```sql 189 | DROP TABLE < 表名 > ; 190 | ``` 191 | * 删除 product 表 192 | 193 | 需要特别注意的是,删除的表是无法恢复的,只能重新插入,请执行删除操作时要特别谨慎。 194 | 195 | ```sql 196 | DROP TABLE product; 197 | ``` 198 | - 添加列的 ALTER TABLE 语句 199 | 200 | ```sql 201 | ALTER TABLE < 表名 > ADD COLUMN < 列的定义 >; 202 | ``` 203 | - 添加一列可以存储100位的可变长字符串的 product_name_pinyin 列 204 | 205 | ```sql 206 | ALTER TABLE product ADD COLUMN product_name_pinyin VARCHAR(100); 207 | ``` 208 | - 删除列的 ALTER TABLE 语句 209 | 210 | ```sql 211 | ALTER TABLE < 表名 > DROP COLUMN < 列名 >; 212 | ``` 213 | - 删除 product_name_pinyin 列 214 | 215 | ```sql 216 | ALTER TABLE product DROP COLUMN product_name_pinyin; 217 | ``` 218 | - 删除表中特定的行(语法) 219 | 220 | ```sql 221 | -- 一定注意添加 WHERE 条件,否则将会删除所有的数据 222 | DELETE FROM product WHERE COLUMN_NAME='XXX'; 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 | ### 1.2.9 索引 371 | 372 | - 索引的作用 373 | 374 | MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。 375 | 376 | 打个比方,如果合理的设计且使用索引的 MySQL 是一辆兰博基尼的话,那么没有设计和使用索引的 MySQL 就是一个人力三轮车。 377 | 378 | 拿汉语字典的目录页(索引)打比方,我们可以按拼音、笔画、偏旁部首等排序的目录(索引)快速查找到需要的字。 379 | 380 | 索引创建了一种有序的数据结构,采用二分法搜索数据时,其复杂度为 ![1](http://latex.codecogs.com/svg.latex?log_2(N)) ,1000多万的数据只要搜索23次,其效率是非常高效的。 381 | 382 | - 如何创建索引 383 | 384 | 创建表时可以直接创建索引,语法如下: 385 | ```sql 386 | CREATE TABLE mytable( 387 | 388 | ID INT NOT NULL, 389 | 390 | username VARCHAR(16) NOT NULL, 391 | 392 | INDEX [indexName] (username(length)) 393 | 394 | ); 395 | ``` 396 | 397 | 也可以使用如下语句创建: 398 | 399 | ```sql 400 | -- 方法1 401 | CREATE INDEX indexName ON table_name (column_name) 402 | 403 | -- 方法2 404 | ALTER table tableName ADD INDEX indexName(columnName) 405 | ``` 406 | 407 | 408 | 409 | - 索引分类 410 | - 主键索引 411 | 412 | 建立在主键上的索引被称为主键索引,一张数据表只能有一个主键索引,索引列值不允许有空值,通常在创建表时一起创建。 413 | 414 | - 唯一索引 415 | 416 | 建立在UNIQUE字段上的索引被称为唯一索引,一张表可以有多个唯一索引,索引列值允许为空,列值中出现多个空值不会发生重复冲突。 417 | 418 | - 普通索引 419 | 420 | 建立在普通字段上的索引被称为普通索引。 421 | 422 | - 前缀索引 423 | 424 | 前缀索引是指对字符类型字段的前几个字符或对二进制类型字段的前几个bytes建立的索引,而不是在整个字段上建索引。前缀索引可以建立在类型为char、varchar、binary、varbinary的列上,可以大大减少索引占用的存储空间,也能提升索引的查询效率。 425 | 426 | - 全文索引 427 | 428 | 利用“分词技术”实现在长文本中搜索关键字的一种索引。 429 | 430 | 语法:`SELECT * FROM article WHERE MATCH (col1,col2,...) AGAINST (expr [ search _ modifier ])` 431 | 432 | 1、MySQL 5.6 以前的版本,只有 MyISAM 存储引擎支持全文索引; 433 | 434 | 2、MySQL 5.6 及以后的版本,MyISAM 和 InnoDB 存储引擎均支持全文索引; 435 | 436 | 3、只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引。 437 | 438 | 4、如果可能,请尽量先创建表并插入所有数据后再创建全文索引,而不要在创建表时就直接创建全文索引,因为前者比后者的全文索引效率要高。 439 | 440 | - 单列索引 441 | 442 | 建立在单个列上的索引被称为单列索引。 443 | 444 | - 联合索引(复合索引、多列索引) 445 | 446 | 建立在多个列上的索引被称为联合索引,又叫复合索引、组合索引。 447 | 448 | 449 | 450 | 451 | 452 | ### 练习题(请给出代码、包含代码及代码执行结果的截图) 453 | 454 | #### 1.1 455 | 456 | 编写一条 CREATE TABLE 语句,用来创建一个包含表 1-A 中所列各项的表 Addressbook (地址簿),并为 regist_no (注册编号)列设置主键约束 457 | 458 | 表1-A 表 Addressbook (地址簿)中的列 459 | 460 | ![图片](./img/ch01/ch01.04%E4%B9%A0%E9%A2%981.png) 461 | 462 | 463 | #### 1.2 464 | 465 | 假设在创建练习1.1中的 Addressbook 表时忘记添加如下一列 postal_code (邮政编码)了,请编写 SQL 把此列添加到 Addressbook 表中。 466 | 467 | 列名 : postal_code 468 | 469 | 数据类型 :定长字符串类型(长度为 8) 470 | 471 | 约束 :不能为 NULL 472 | 473 | 474 | 475 | #### 1.3 填空题 476 | 477 | 请补充如下 SQL 语句来删除 Addressbook 表。 478 | 479 | ```sql 480 | ( ) table Addressbook; 481 | ``` 482 | 483 | #### 1.4 判断题 484 | 485 | 是否可以编写 SQL 语句来恢复删除掉的 Addressbook 表? 486 | -------------------------------------------------------------------------------- /ch02_基础查询与排序.md: -------------------------------------------------------------------------------- 1 | # 第二章:基础查询与排序 2 | 3 | ## 2.1 SELECT语句基础 4 | 5 | ### 2.1.1 从表中选取数据 6 | 7 | #### SELECT语句 8 | 9 | 从表中选取数据时需要使用SELECT语句,也就是只从表中选出(SELECT)必要数据的意思。通过SELECT语句查询并选取出必要数据的过程称为匹配查询或查询(query)。 10 | 11 | 基本SELECT语句包含了SELECT和FROM两个子句(clause)。示例如下: 12 | 13 | ```sql 14 | SELECT <列名>, 15 | FROM <表名>; 16 | ``` 17 | 其中,SELECT子句中列举了希望从表中查询出的列的名称,而FROM子句则指定了选取出数据的表的名称。 18 | 19 | ### 2.1.2 从表中选取符合条件的数据 20 | 21 | #### WHERE语句 22 | 23 | 当不需要取出全部数据,而是选取出满足“商品种类为衣服”“销售单价在1000日元以上”等某些条件的数据时,使用WHERE语句。 24 | 25 | SELECT 语句通过WHERE子句来指定查询数据的条件。在WHERE 子句中可以指定“某一列的值和这个字符串相等”或者“某一列的值大于这个数字”等条件。执行含有这些条件的SELECT语句,就可以查询出只符合该条件的记录了。 26 | 27 | ```sql 28 | SELECT <列名>, …… 29 | FROM <表名> 30 | WHERE <条件表达式>; 31 | ``` 32 | 比较下面两者输出结果的不同: 33 | ```sql 34 | -- 用来选取product type列为衣服的记录的SELECT语句 35 | SELECT product_name, product_type 36 | FROM product 37 | WHERE product_type = '衣服'; 38 | -- 也可以选取出不是查询条件的列(条件列与输出列不同) 39 | SELECT product_name 40 | FROM product 41 | WHERE product_type = '衣服'; 42 | ``` 43 | 44 | ### 2.1.3 相关法则 45 | 46 | * 星号(*)代表全部列的意思。 47 | * SQL 中可以随意使用换行符,不影响语句执行(但不可插入空行)。 48 | * 设定汉语别名时需要使用双引号(")括起来。 49 | * 在 SELECT 语句中使用 `DISTINCT` 可以剔除重复行。 50 | * 注释是 SQL 语句中用来标识说明或者注意事项的部分。分为1行注释"-- "和多行注释两种"/* */"。 51 | ```sql 52 | -- 想要查询出全部列时,可以使用代表所有列的星号(*)。 53 | SELECT * 54 | FROM <表名>; 55 | -- SQL语句可以使用AS关键字为列设定别名(用中文时需要双引号(“”))。 56 | SELECT product_id As id, 57 | product_name As name, 58 | purchase_price AS "进货单价" 59 | FROM product; 60 | -- 使用 `DISTINCT` 剔除 `product_type` 列中重复的数据 61 | SELECT DISTINCT product_type 62 | FROM product; 63 | ``` 64 | 65 | ## 2.2 算术运算符和比较运算符 66 | 67 | ### 2.2.1 算术运算符 68 | 69 | SQL语句中可以使用的四则运算的主要运算符如下: 70 | 71 | |含义|运算符| 72 | |:----|:----| 73 | |加法|+| 74 | |减法|-| 75 | |乘法|*| 76 | |除法|/| 77 | 78 | ### 2.2.2 比较运算符 79 | 80 | ```sql 81 | -- 选取出sale_price列为500的记录 82 | SELECT product_name, product_type 83 | FROM product 84 | WHERE sale_price = 500; 85 | ``` 86 | SQL常见比较运算符如下: 87 | |运算符|含义| 88 | |:----|:----| 89 | | = |和 ~ 相等| 90 | | <> |和 ~ 不相等| 91 | | >= |大于等于 ~ | 92 | | > |大于 ~ | 93 | | <= |小于等于 ~ | 94 | | < |小于 ~ | 95 | 96 | ### 2.2.3 常用法则 97 | 98 | * SELECT子句中可以使用常数或者表达式。 99 | * 使用比较运算符时一定要注意不等号和等号的位置。 100 | * 字符串类型的数据原则上按照字典顺序进行排序,不能与数字的大小顺序混淆。 101 | * 希望选取NULL记录时,需要在条件表达式中使用IS NULL运算符。希望选取不是NULL的记录时,需要在条件表达式中使用IS NOT NULL运算符。 102 | 103 | 相关代码如下: 104 | 105 | ```sql 106 | -- SQL语句中也可以使用运算表达式 107 | SELECT product_name, sale_price, sale_price * 2 AS "sale_price x2" 108 | FROM product; 109 | -- WHERE子句的条件表达式中也可以使用计算表达式 110 | SELECT product_name, sale_price, purchase_price 111 | FROM product 112 | WHERE sale_price - purchase_price >= 500; 113 | /* 对字符串使用不等号 114 | 首先创建chars并插入数据 115 | 选取出大于‘2’的SELECT语句*/ 116 | -- DDL:创建表 117 | CREATE TABLE chars 118 | (chr CHAR(3)NOT NULL, 119 | PRIMARY KEY(chr)); 120 | -- 选取出大于'2'的数据的SELECT语句('2'为字符串) 121 | SELECT chr 122 | FROM chars 123 | WHERE chr > '2'; 124 | -- 选取NULL的记录 125 | SELECT product_name, purchase_price 126 | FROM product 127 | WHERE purchase_price IS NULL; 128 | -- 选取不为NULL的记录 129 | SELECT product_name, purchase_price 130 | FROM product 131 | WHERE purchase_price IS NOT NULL; 132 | ``` 133 | 134 | ## 2.3 逻辑运算符 135 | 136 | ### 2.3.1 NOT运算符 137 | 138 | 想要表示 `不是……` 时,除了前文的<>运算符外,还存在另外一个表示否定、使用范围更广的运算符:NOT。 139 | 140 | NOT不能单独使用,必须和其他查询条件组合起来使用。如下例: 141 | 142 | 选取出销售单价大于等于1000日元的记录 143 | 144 | ```sql 145 | SELECT product_name, product_type, sale_price 146 | FROM product 147 | WHERE sale_price >= 1000; 148 | ``` 149 | 查询结果如下: 150 | 151 | ![图片](./img/ch02/ch02.00-not-230.png) 152 | 153 | 向上述 SELECT 语句的查询条件中添加NOT运算符 154 | 155 | ```sql 156 | SELECT product_name, product_type, sale_price 157 | FROM product 158 | WHERE NOT sale_price >= 1000; 159 | ``` 160 | 查询结果如下: 161 | 162 | ![图片](./img/ch02/ch02.00-not-231.png) 163 | 164 | 可以看出,通过否定销售单价大于等于 1000 日元 (sale_price >= 1000) 这个查询条件,选取出了销售单价小于 1000 日元的商品。也就是说 `NOT sale_price >= 1000` 与 `sale_price < 1000` 是等价的。 165 | 166 | 值得注意的是,虽然通过 NOT 运算符否定一个条件可以得到相反查询条件的结果,但是其可读性明显不如显式指定查询条件,因此,不可滥用该运算符。 167 | 168 | ### 2.3.2 AND运算符和OR运算符 169 | 170 | 当希望同时使用多个查询条件时,可以使用AND或者OR运算符。 171 | 172 | AND 相当于“并且”,类似数学中的取交集; 173 | 174 | OR 相当于“或者”,类似数学中的取并集。 175 | 176 | 如下图所示: 177 | 178 | AND运算符工作效果图 179 | 180 | ![图片](./img/ch02/ch02.01and.png) 181 | 182 | OR运算符工作效果图 183 | 184 | ![图片](./img/ch02/ch02.02or.png) 185 | 186 | #### 通过括号优先处理 187 | 188 | 如果要查找这样一个商品,该怎么处理? 189 | 190 | >“商品种类为办公用品”并且“登记日期是 2009 年 9 月 11 日或者 2009 年 9 月 20 日” 191 | >理想结果为“打孔器”,但当你输入以下信息时,会得到错误结果 192 | ```sql 193 | -- 将查询条件原封不动地写入条件表达式,会得到错误结果 194 | SELECT product_name, product_type, regist_date 195 | FROM product 196 | WHERE product_type = '办公用品' 197 | AND regist_date = '2009-09-11' 198 | OR regist_date = '2009-09-20'; 199 | ``` 200 | 错误的原因是 **AND 运算符优先于 OR 运算符** ,想要优先执行OR运算,可以使用 **括号** : 201 | ```sql 202 | -- 通过使用括号让OR运算符先于AND运算符执行 203 | SELECT product_name, product_type, regist_date 204 | FROM product 205 | WHERE product_type = '办公用品' 206 | AND ( regist_date = '2009-09-11' 207 | OR regist_date = '2009-09-20'); 208 | ``` 209 | 210 | 运算符优先级请参考下图 211 | 212 | ![image](https://user-images.githubusercontent.com/26516464/177024042-2a2dff90-9864-4ab8-920f-65fb9c5d64f2.png) 213 | 214 | 215 | ### 2.3.3 真值表 216 | 217 | 复杂运算时该怎样理解? 218 | 219 | 当碰到条件较复杂的语句时,理解语句含义并不容易,这时可以采用**真值表**来梳理逻辑关系。 220 | 221 | 什么是真值? 222 | 223 | 本节介绍的三个运算符 NOT、AND 和 OR 称为逻辑运算符。这里所说的逻辑就是对真值进行操作的意思。**真值**就是值为真(TRUE)或假 (FALSE)其中之一的值。 224 | 225 | 例如,对于 sale_price >= 3000 这个查询条件来说,由于 product_name 列为 '运动 T 恤' 的记录的 sale_price 列的值是 2800,因此会返回假(FALSE),而 product_name 列为 '高压锅' 的记录的sale_price 列的值是 5000,所以返回真(TRUE)。 226 | 227 | **AND 运算符**两侧的真值都为真时返回真,除此之外都返回假。 228 | 229 | **OR 运算符**两侧的真值只要有一个不为假就返回真,只有当其两侧的真值都为假时才返回假。 230 | 231 | **NOT运算符**只是单纯的将真转换为假,将假转换为真。 232 | 233 | 真值表 234 | 235 | ![图片](./img/ch02/ch02.03true.png) 236 | 237 | 查询条件为P AND(Q OR R)的真值表 238 | 239 | ![图片](./img/ch02/ch02.04true2.png) 240 | 241 | #### 含有NULL时的真值 242 | 243 | NULL的真值结果既不为真,也不为假,因为并不知道这样一个值。 244 | 245 | 那该如何表示呢? 246 | 247 | 这时真值是除真假之外的第三种值——**不确定**(UNKNOWN)。一般的逻辑运算并不存在这第三种值。SQL 之外的语言也基本上只使用真和假这两种真值。与通常的逻辑运算被称为二值逻辑相对,只有 SQL 中的逻辑运算被称为三值逻辑。 248 | 249 | 三值逻辑下的AND和OR真值表为: 250 | 251 | ![图片](./img/ch02/ch02.05true3.png) 252 | 253 | 254 | ### 练习题-第一部分(请给出代码、包含代码及代码执行结果的截图) 255 | 256 | #### 2.1 257 | 258 | 编写一条SQL语句,从 `product`(商品) 表中选取出“登记日期(`regist_date`)在2009年4月28日之后”的商品,查询结果要包含 `product_name` 和 `regist_date` 两列。 259 | 260 | #### 2.2 261 | 262 | 请说出对product 表执行如下3条SELECT语句时的返回结果。 263 | 264 | ① 265 | 266 | ```sql 267 | SELECT * 268 | FROM product 269 | WHERE purchase_price = NULL; 270 | ``` 271 | ② 272 | ```sql 273 | SELECT * 274 | FROM product 275 | WHERE purchase_price <> NULL; 276 | ``` 277 | ③ 278 | ```sql 279 | SELECT * 280 | FROM product 281 | WHERE product_name > NULL; 282 | ``` 283 | 284 | #### 2.3 285 | 286 | `2.2.3` 章节中的SELECT语句能够从 `product` 表中取出“销售单价(`sale_price`)比进货单价(`purchase_price`)高出500日元以上”的商品。请写出两条可以得到相同结果的SELECT语句。执行结果如下所示: 287 | 288 | ```sql 289 | product_name | sale_price | purchase_price 290 | -------------+------------+------------ 291 | T恤衫 |   1000 | 500 292 | 运动T恤 | 4000 | 2800 293 | 高压锅 | 6800 | 5000 294 | ``` 295 | 296 | #### 2.4 297 | 298 | 请写出一条SELECT语句,从 `product` 表中选取出满足“销售单价打九折之后利润高于 `100` 日元的办公用品和厨房用具”条件的记录。查询结果要包括 `product_name`列、`product_type` 列以及销售单价打九折之后的利润(别名设定为 `profit`)。 299 | 300 | 提示:销售单价打九折,可以通过 `sale_price` 列的值乘以0.9获得,利润可以通过该值减去 `purchase_price` 列的值获得。 301 | 302 | ## 2.4 对表进行聚合查询 303 | 304 | ### 2.4.1 聚合函数 305 | 306 | SQL中用于汇总的函数叫做聚合函数。以下五个是最常用的聚合函数: 307 | 308 | - SUM:计算表中某数值列中的合计值 309 | 310 | - AVG:计算表中某数值列中的平均值 311 | 312 | - MAX:计算表中任意列中数据的最大值,包括文本类型和数字类型 313 | 314 | - MIN:计算表中任意列中数据的最小值,包括文本类型和数字类型 315 | 316 | - COUNT:计算表中的记录条数(行数) 317 | 318 | 请使用 `shop` 数据库,执行以下 SQL 查询语句,理解并掌握聚合函数的常规用法: 319 | 320 | ```sql 321 | -- 计算销售单价和进货单价的合计值 322 | SELECT SUM(sale_price), SUM(purchase_price) 323 | FROM product; 324 | -- 计算销售单价和进货单价的平均值 325 | SELECT AVG(sale_price), AVG(purchase_price) 326 | FROM product; 327 | -- 计算销售单价的最大值和最小值 328 | SELECT MAX(sale_price), MIN(sale_price) 329 | FROM product; 330 | -- MAX和MIN也可用于非数值型数据 331 | SELECT MAX(regist_date), MIN(regist_date) 332 | FROM product; 333 | -- 计算全部数据的行数(包含 NULL 所在行) 334 | SELECT COUNT(*) 335 | FROM product; 336 | -- 计算 NULL 以外数据的行数 337 | SELECT COUNT(purchase_price) 338 | FROM product; 339 | ``` 340 | 341 | #### 使用 DISTINCT 进行删除重复值的聚合运算 342 | 343 | 当对整表进行聚合运算时,表中可能存在多行相同的数据,比如商品类型(product_type 列)。 344 | 345 | 在某些场景下,就不能直接使用聚合函数进行聚合运算了,必须搭配 `DISTINCT` 函数使用。 346 | 347 | 比如:要计算总共有几种咖啡类型在售,该怎么计算呢? 348 | 349 | 如前所述,`DISTINCT` 函数用于删除重复数据,应用 COUNT 聚合函数之前,加上 `DISTINCT` 关键字就可以实现需求。 350 | 351 | ```SQL 352 | SELECT COUNT(DISTINCT product_type) 353 | FROM product; 354 | ``` 355 | 356 | ### 2.4.2 聚合函数应用法则 357 | 358 | - COUNT 聚合函数运算结果与参数有关,COUNT(*) / COUNT(1) 得到包含 NULL 值的所有行,COUNT(<列名>) 得到不包含 NULL 值的所有行。 359 | 360 | - 聚合函数不处理包含 NULL 值的行,但是 COUNT(*) 除外。 361 | 362 | - MAX / MIN 函数适用于文本类型和数字类型的列,而 SUM / AVG 函数仅适用于数字类型的列。 363 | 364 | - 在聚合函数的参数中使用 DISTINCT 关键字,可以得到删除重复值的聚合结果。 365 | 366 | ## 2.5 对表进行分组 367 | 368 | ### 2.5.1 GROUP BY语句 369 | 370 | 之前使用聚合函数都是会将整个表的数据进行处理,当你想将进行分组汇总时(即:将现有的数据按照某列来汇总统计),GROUP BY可以帮助你: 371 | 372 | ```sql 373 | SELECT <列名1>,<列名2>, <列名3>, …… 374 | FROM <表名> 375 | GROUP BY <列名1>, <列名2>, <列名3>, ……; 376 | ``` 377 | 看一看是否使用GROUP BY语句的差异: 378 | ```sql 379 | -- 按照商品种类统计数据行数 380 | SELECT product_type, COUNT(*) 381 | FROM product 382 | GROUP BY product_type; 383 | -- 不含GROUP BY 384 | SELECT product_type, COUNT(*) 385 | FROM product 386 | ``` 387 | 按照商品种类对表进行切分 388 | 389 | ![图片](./img/ch02/ch02.06cut.png) 390 | 391 | 这样,GROUP BY 子句就像切蛋糕那样将表进行了分组。在 GROUP BY 子句中指定的列称为**聚合键**或者**分组列**。 392 | 393 | #### 聚合键中包含NULL时 394 | 395 | 将进货单价(purchase_price)作为聚合键举例: 396 | 397 | ```sql 398 | SELECT purchase_price, COUNT(*) 399 | FROM product 400 | GROUP BY purchase_price; 401 | ``` 402 | 此时会将NULL作为一组特殊数据进行聚合运算 403 | 404 | #### GROUP BY书写位置 405 | 406 | GROUP BY的子句书写顺序有严格要求,不按要求会导致SQL无法正常执行,目前出现过的子句顺序为: 407 | 408 | 1. SELECT :arrow_right: 2. FROM :arrow_right: 3. WHERE :arrow_right: 4. GROUP BY 409 | 410 | 其中前三项用于筛选数据,GROUP BY对筛选出的数据进行处理 411 | 412 | #### 在WHERE子句中使用GROUP BY 413 | 414 | ```sql 415 | SELECT purchase_price, COUNT(*) 416 | FROM product 417 | WHERE product_type = '衣服' 418 | GROUP BY purchase_price; 419 | ``` 420 | 421 | ### 2.5.2 常见错误 422 | 423 | 在使用聚合函数及GROUP BY子句时,经常出现的错误有: 424 | 425 | 1. 在聚合函数的 SELECT 子句中写了聚合键以外的列使用 COUNT 等聚合函数时,SELECT 子句中如果出现列名,只能是 GROUP BY 子句中指定的列名(也就是聚合键)。 426 | 2. 在 GROUP BY 子句中使用列的别名 SELECT 子句中可以通过 AS 来指定别名,但在 GROUP BY 中不能使用别名。因为在 DBMS 中 ,SELECT 子句在 GROUP BY 子句后执行。 427 | 3. 在 WHERE 中使用聚合函数原因是聚合函数的使用前提是结果集已经确定,而 WHERE 还处于确定结果集的过程中,所以相互矛盾会引发错误。 如果想指定条件,可以在 SELECT,HAVING(下面马上会讲)以及O RDER BY 子句中使用聚合函数。 428 | 429 | ## 2.6 为聚合结果指定条件 430 | 431 | ### 2.6.1 用 HAVING 得到特定分组 432 | 433 | 前面学习了如何得到分组聚合结果,现在大家思考一下,如何得到分组聚合结果的部分结果呢? 434 | 435 | 将表使用 GROUP BY 分组后,怎样才能只取出其中两组? 436 | 437 | ![图片](./img/ch02/ch02.07groupby.png) 438 | 439 | 这里 WHERE 不可行,因为,WHERE子句只能指定记录(行)的条件,而不能用来指定组的条件(例如,“数据行数为 2 行”或者“平均值为 500”等)。 440 | 441 | 可以在 GROUP BY 后使用 HAVING 子句。 442 | 443 | HAVING 的用法类似 WHERE。 444 | 445 | 值得注意的是:HAVING 子句必须与 GROUP BY 子句配合使用,且限定的是分组聚合结果,WHERE 子句是限定数据行(包括分组列),二者各司其职,不要混淆。 446 | 447 | ### 2.6.2 HAVING特点 448 | 449 | HAVING子句用于对分组进行过滤,可以使用常数、聚合函数和GROUP BY中指定的列名(聚合键)。 450 | 451 | ```sql 452 | -- 常数 453 | SELECT product_type, COUNT(*) 454 | FROM product 455 | GROUP BY product_type 456 | HAVING COUNT(*) = 2; 457 | 458 | -- 错误形式(因为product_name不包含在GROUP BY聚合键中) 459 | SELECT product_type, COUNT(*) 460 | FROM product 461 | GROUP BY product_type 462 | HAVING product_name = '圆珠笔'; 463 | ``` 464 | 465 | ## 2.7 对查询结果进行排序 466 | 467 | ### 2.7.1 ORDER BY 468 | 469 | 在某些场景下,需要得到一个排序之后的结果,比如运动员在奥运赛场的得分,组委会用得分倒序结果来判定金银铜牌到底花落谁家。而 SQL 语句执行结果默认随机排列,想要按照顺序排序,需使用 **ORDER BY** 子句。 470 | 471 | ```sql 472 | SELECT <列名1>, <列名2>, <列名3>, …… 473 | FROM <表名> 474 | ORDER BY <排序基准列1> [ASC, DESC], <排序基准列2> [ASC, DESC], …… 475 | ``` 476 | 477 | 其中,参数 ASC 表示升序排列,DESC 表示降序排列,默认为升序,此时,参数 ASC 可以缺省。 478 | 479 | 如下代码将得到按照销售价格倒序排列的查询结果: 480 | 481 | ```sql 482 | -- 降序排列 483 | SELECT product_id, product_name, sale_price, purchase_price 484 | FROM product 485 | ORDER BY sale_price DESC; 486 | ``` 487 | 488 | 如果有多列排序需求,只需在 ORDER BY 子句中依次书写排序列 + 排序参数即可,详见如下代码: 489 | 490 | ```SQL 491 | -- 多个排序键 492 | SELECT product_id, product_name, sale_price, purchase_price 493 | FROM product 494 | ORDER BY sale_price, product_id; 495 | ``` 496 | 497 | 需要特别说明的是:由于 NULL 无法使用比较运算符进行比较,也就是说,无法与文本类型,数字类型,日期类型等进行比较,当排序列存在 NULL 值时,NULL 结果会展示在查询结果的开头或者末尾。 498 | 499 | ```SQL 500 | -- 当用于排序的列名中含有NULL时,NULL会在开头或末尾进行汇总。 501 | SELECT product_id, product_name, sale_price, purchase_price 502 | FROM product 503 | ORDER BY purchase_price; 504 | ``` 505 | 506 | ### 2.7.2 ORDER BY 子句中使用别名 507 | 508 | 前文讲GROUP BY中提到,GROUP BY 子句中不能使用SELECT 子句中定义的别名,但是在 ORDER BY 子句中却可以使用别名。为什么在GROUP BY中不可以而在ORDER BY中可以呢? 509 | 510 | 这是因为 SQL 在使用 HAVING 子句时 SELECT 语句的执行顺序为: 511 | 512 | FROM → WHERE → GROUP BY → SELECT → HAVING → ORDER BY 513 | 514 | 其中 SELECT 的执行顺序在 GROUP BY 子句之后,ORDER BY 子句之前。 515 | 516 | 当在 ORDER BY 子句中使用别名时,已经知道了 SELECT 子句设置的别名,但是在 GROUP BY 子句执行时还不知道别名的存在,所以在 ORDER BY 子句中可以使用别名,但是在GROUP BY中不能使用别名。 517 | 518 | ### 2.7.3 ORDER BY 遇上 NULL 519 | 520 | 在MySQL中,`NULL` 值被认为比任何 `非NULL` 值低,因此,当顺序为 ASC(升序)时,`NULL` 值出现在第一位,而当顺序为 DESC(降序)时,则排序在最后。 521 | 522 | 如果想指定存在 `NULL` 的行出现在首行或者末行,需要特殊处理。 523 | 524 | 使用如下代码构建示例表: 525 | 526 | ```sql 527 | CREATE TABLE user ( 528 | id INT NOT NULL AUTO_INCREMENT, 529 | name VARCHAR(50), 530 | date_login DATE, 531 | PRIMARY KEY (id) 532 | ); 533 | 534 | INSERT INTO user(name, date_login) VALUES 535 | (NULL, '2017-03-12'), 536 | ('john', NULL), 537 | ('david', '2016-12-24'), 538 | ('zayne', '2017-03-02'); 539 | ``` 540 | 既然排序时,`NULL` 的值比 `非NULL` 值低(可以理解为 `0` 或者 `-∞`),那么我们在排序时就要对这个默认情况进行特殊处理以达到想要的效果。 541 | 542 | 一般有如下两种需求: 543 | 544 | - 将 `NULL` 值排在末行,同时将所有 `非NULL` 值按升序排列。 545 | 546 | 对于数字或者日期类型,可以在排序字段前添加一个负号(minus)来得到反向排序。(`-1、-2、-3....-∞`) 547 | 548 | ```SQL 549 | SELECT * FROM user 550 | ORDER BY -date_login DESC; 551 | ``` 552 | 553 | ![图片](./img/ch02/ch02.07_null_last1.jpg) 554 | 555 | 对于字符型或者字符型数字,此方法不一定能得到期望的排序结果,可以使用 `IS NULL` 比较运算符。另外 `ISNULL( )` 函数等同于使用 `IS NULL` 比较运算符。 556 | 557 | ```SQL 558 | -- IS NULL 559 | SELECT * FROM user 560 | ORDER BY name IS NULL ASC,name ASC; 561 | 562 | -- ISNULL() 563 | SELECT * FROM user 564 | ORDER BY ISNULL(name) ASC,name ASC; 565 | ``` 566 | 567 | ![图片](./img/ch02/ch02.07_null_last2.jpg) ![图片](./img/ch02/ch02.07_null_last3.jpg) 568 | 569 | 上述语句先使用 `ISNULL(name)` 字段进行升序排列,而只有当 `name` 列值为 `NULL` 时,`ISNULL(name)` 才为真,所以其排到末行,而 `name ASC` 则实现了 `非NULL` 值升序排列。 570 | 571 | 还可以使用 `COALESCE` 函数实现需求 572 | 573 | ```SQL 574 | SELECT * FROM user 575 | ORDER BY COALESCE(name, 'zzzzz') ASC; 576 | ``` 577 | 578 | ![图片](./img/ch02/ch02.07_null_last4.jpg) 579 | 580 | - 将 `NULL` 值排在首行,同时将所有 `非NULL` 值按倒序排列。 581 | 582 | 对于数字或者日期类型,可以在排序字段前添加一个负号(minus)来实现。(`-∞...-3、-2、-1`) 583 | 584 | ```SQL 585 | SELECT * FROM user 586 | ORDER BY -date_login ASC; 587 | ``` 588 | 589 | ![图片](./img/ch02/ch02.07_null_first1.jpg) 590 | 591 | 对于字符型或者字符型数字,此方法不一定能得到期望的排序结果,可以使用 `IS NOT NULL` 比较运算符。另外 `!ISNULL( )` 函数等同于使用 `IS NOT NULL` 比较运算符。 592 | 593 | ```SQL 594 | -- IS NOT NULL 595 | SELECT * FROM user 596 | ORDER BY name IS NOT NULL ASC,name DESC; 597 | 598 | -- !ISNULL() 599 | SELECT * FROM user 600 | ORDER BY !ISNULL(name) ASC,name DESC; 601 | ``` 602 | 603 | ![图片](./img/ch02/ch02.07_null_first2.jpg) ![图片](./img/ch02/ch02.07_null_first3.jpg) 604 | 605 | 上述语句先使用 `!ISNULL(name)` 字段进行升序排列,而只有当 `name` 列值不为 `NULL` 时,`!ISNULL(name)` 才为真,所以其排到说行,而 `name DESC` 则实现了 `非NULL` 值降序排列。 606 | 607 | 还可以使用 `COALESCE` 函数实现需求 608 | 609 | ```SQL 610 | SELECT * FROM user 611 | ORDER BY COALESCE(name, 'zzzzz') DESC; 612 | ``` 613 | 614 | ![图片](./img/ch02/ch02.07_null_first4.jpg) 615 | 616 | ### 练习题-第二部分(请给出代码、包含代码及代码执行结果的截图) 617 | 618 | #### 2.5 619 | 620 | 请指出下述SELECT语句中所有的语法错误。 621 | 622 | ```sql 623 | SELECT product_id, SUM(product_name) 624 | --本SELECT语句中存在错误。 625 | FROM product 626 | GROUP BY product_type 627 | WHERE regist_date > '2009-09-01'; 628 | ``` 629 | #### 2.6 630 | 631 | 请编写一条SELECT语句,求出销售单价( `sale_price` 列)合计值大于进货单价( `purchase_price` 列)合计值1.5倍的商品种类。执行结果如下所示。 632 | 633 | ```sql 634 | product_type | sum | sum 635 | -------------+------+------ 636 | 衣服 | 5000 | 3300 637 | 办公用品 | 600 | 320 638 | ``` 639 | ![图片](./img/ch02/ch02.08test26.png) 640 | 641 | #### 2.7 642 | 643 | 此前我们曾经使用SELECT语句选取出了product(商品)表中的全部记录。当时我们使用了 `ORDER BY` 子句来指定排列顺序,但现在已经无法记起当时如何指定的了。请根据下列执行结果,思考 `ORDER BY` 子句的内容。 644 | 645 | ![图片](./img/ch02/ch02.09test27.png) 646 | -------------------------------------------------------------------------------- /ch04_集合运算.md: -------------------------------------------------------------------------------- 1 | # 第四章:集合运算 2 | 3 | # 4.1 表的加减法 4 | 5 | ## 4.1.1 什么是集合运算 6 | 7 | `集合`在数学领域表示“各种各样的事物的总和”,在数据库领域表示记录的集合。具体来说,表、视图和查询的执行结果都是记录的集合,其中的元素为表或者查询结果中的每一行。 8 | 9 | 在标准 SQL 中,分别对检索结果使用 `UNION`,`INTERSECT`, `EXCEPT` 来将检索结果进行并集、交集和差集运算,像`UNION`,`INTERSECT`,`EXCEPT`这种用来进行集合运算的运算符称为集合运算符。 10 | 11 | 以下的文氏图展示了几种集合的基本运算。 12 | 13 | ![图片](./img/ch04/ch04.01.png) 14 | 15 | ![图片](./img/ch04/ch04.02.png) 16 | 17 | [图片来源于网络] 18 | 19 | 在数据库中,所有的表--以及查询结果--都可以视为集合,因此也可以把表视为集合进行上述集合运算,在很多时候,这种抽象非常有助于对复杂查询问题给出一个可行的思路。 20 | 21 | ## 4.1.2 表的加法--UNION 22 | 23 | ### 4.1.2.1 UNION 24 | 25 | 建表代码及数据导入请使用第一章提供的代码。 26 | 27 | 接下来我们演示UNION的具体用法及查询结果: 28 | 29 | ```sql 30 | SELECT product_id, product_name 31 | FROM product 32 | UNION 33 | SELECT product_id, product_name 34 | FROM product2; 35 | ``` 36 | 上述结果包含了两张表中的全部商品。你会发现,这就是我们在学校学过的集合中的并集运算,通过文氏图会看得更清晰(图 7-1): 37 | 38 | ![图片](./img/ch04/ch04.03union.png) 39 | 40 | 通过观察可以发现,商品编号为“ 0001 ”~“ 0003 ”的 3 条记录在两个表中都存在,因此大家可能会认为结果中会出现重复的记录,但是 **UNION 等集合运算符通常都会除去重复的记录**。 41 | 42 | 上述查询是对不同的两张表进行求并集运算,对于同一张表,实际上也是可以进行求并集运算的。 43 | 44 | **练习题:** 45 | 46 | 假设连锁店想要增加成本利润率超过 50% 或者售价低于 800 的货物的存货量,请使用 UNION 对分别满足上述两个条件的商品的查询结果求并集。 47 | 48 | 结果应该类似于: 49 | 50 | ![图片](./img/ch04/ch04.04result.png) 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 | 在前面的章节中我们发现,SQL 语句的 UNION 会对两个查询的结果集进行合并和去重,这种去重不仅会去掉两个结果集相互重复的,还会去掉一个结果集中的重复行。但在实践中有时候需要需要不去重的并集,在 UNION 的结果中保留重复行的语法其实非常简单,只需要在 UNION 后面添加 ALL 关键字就可以了。 113 | 114 | 例如,想要知道 product 和 product2 中所包含的商品种类,首先需要将两个表的商品种类字段选出来,然后使用 UNION ALL 进行不去重合并,详见如下查询代码。 115 | 116 | ```sql 117 | -- 保留重复行 118 | SELECT product_type 119 | FROM product 120 | UNION ALL 121 | SELECT product_type 122 | FROM product2; 123 | ``` 124 | 查询结果如下: 125 | 126 | ![图片](./img/ch04/ch04.05result2_new.png) 127 | 128 | **练习题:** 129 | 130 | 商店决定对product表中成本利润低于 50% **或者** 售价低于1000的商品提价,请使用UNION ALL 语句将分别满足上述两个条件的结果取并集。查询结果类似下表: 131 | 132 | ![图片](./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 | 146 | ### 4.1.2.4 隐式数据类型转换 147 | 148 | 通常来说, 我们会把类型完全一致,并且代表相同属性的列使用 UNION 合并到一起显示,但有时候,即使数据类型不完全相同,也会通过隐式类型转换来将两个类型不同的列放在一列里显示,例如字符串和数值类型: 149 | 150 | ```sql 151 | SELECT product_id, product_name, '1' 152 |   FROM product 153 | UNION 154 | SELECT product_id, product_name,sale_price 155 |   FROM product2; 156 | ``` 157 | 上述查询能够正确执行,得到如下结果: 158 | 159 | ![图片](./img/ch04/ch04.07result4.png) 160 | 161 | **另外,需要注意的是在 hive 中进行 join 关联查询时,关联列要避免使用隐式数据类型转换,否则容易导致数据倾斜** 162 | 163 | **练习题:** 164 | 165 | 使用 SYSDATE() 函数可以返回当前日期时间,其返回值是一个日期时间类型的数据,请测试该数据类型和数值,字符串等类型的兼容性。 166 | 167 | 测试方法: 168 | 169 | 如果以下代码可以正确执行,则说明时间日期类型和字符串,数值以及缺失值均能兼容。 170 | 171 | ```sql 172 | SELECT SYSDATE(),SYSDATE(),SYSDATE() 173 | UNION 174 | SELECT 'chars',123,null; 175 | ``` 176 | 事实证明,以上代码可以正确执行,查询结果参考下图: 177 | 178 | ![图片](./img/ch04/ch04.08result5.png) 179 | 180 | ## 4.1.3 MySQL 8.0 交集运算符 INTERSECT 181 | 182 | 集合的交,就是两个集合的公共部分,由于集合元素的互异性,集合的交只需通过文氏图就可以很直观地看到它的意义。 183 | 184 | 截止到 MySQL 8.0.30 版本,MySQL 仍然不支持 INTERSECT 操作。 185 | 186 | ```sql 187 | SELECT product_id, product_name 188 | FROM product 189 | INTERSECT 190 | SELECT product_id, product_name 191 | FROM product2; 192 | ``` 193 | >错误代码:1064 194 | >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 195 | >FROM product2 196 | 197 | 此时需要用 inner join 来求得交集 198 | ```sql 199 | SELECT p1.product_id, p1.product_name 200 | FROM product p1 201 | INNER JOIN product2 p2 202 | ON p1.product_id=p2.product_id; 203 | ``` 204 | 205 | 可喜的是,MySQL 8.0.31 已经支持 `INTERSECT ` 运算符了,而且非常简单,使用 `INTERSECT ` 求交集代码如下: 206 | ```sql 207 | TABLE product INTERSECT TABLE product2; 208 | ``` 209 | 210 | 需要注意的是:使用 `INTERSECT` 运算符进行交集运算的两张表的列数必须相同,**字段类型也需要相同。** 211 | 212 | `INTERSECT` 运算符优先级高于 `UNION` 和 `EXCEPT` ,同时出现时会优先进行交集运算,如下两条SQL语句是等价的。 213 | 214 | ```sql 215 | TABLE r EXCEPT TABLE s INTERSECT TABLE t; 216 | 217 | TABLE r EXCEPT (TABLE s INTERSECT TABLE t); 218 | ``` 219 | 220 | ## 4.1.4 差集,补集与表的减法 221 | 222 | 求集合差集的减法运算和实数的减法运算有些不同,当使用一个集合A减去另一个集合B的时候,对于只存在于集合B而不存在于集合A的元素,采取直接忽略的策略,因此集合A和B做减法只是将集合A中也同时属于集合B的元素减掉。 223 | 224 | ![图片](./img/ch04/ch04.09except.png) 225 | 226 | ### 4.1.4.1 MySQL 8.0 差集运算符 EXCEPT 227 | 228 | MySQL 8.0.31 之前的版本不支持 表的减法运算符 EXCEPT。可以借助之前学过的NOT IN 谓词实现表的减法(差集运算)。 229 | 230 | **练习题:** 231 | 232 | 找出只存在于product表但不存在于product2表的商品。 233 | 234 | ```sql 235 | -- 使用 NOT IN 子句的实现方法 236 | SELECT * 237 | FROM product 238 | WHERE product_id NOT IN (SELECT product_id 239 |   FROM product2); 240 | ``` 241 | 使用 MySQL 8.0.31 版本进行差集运算的语句如下: 242 | ```sql 243 | TABLE product EXCEPT TABLE product2; 244 | ``` 245 | 246 | ### 4.1.4.2 EXCEPT 与 NOT 谓词 247 | 248 | 通过上述练习题的MySQL解法,我们发现,使用 NOT IN 谓词,基本上可以实现和SQL标准语法中的EXCEPT运算相同的效果。 249 | 250 | **练习题:** 251 | 252 | 使用NOT谓词进行集合的减法运算,求出 product 表中,售价高于2000、成本利润率不低于 30% 的商品,结果应该如下表所示。 253 | 254 | ![图片](./img/ch04/ch04.10.png) 255 | 256 | 参考答案: 257 | 258 | ```sql 259 | SELECT * 260 | FROM product 261 | WHERE sale_price > 2000 262 | AND product_id NOT IN (SELECT product_id 263 | FROM product 264 | WHERE sale_price < 1.3*purchase_price); 265 | ``` 266 | 267 | ### 4.1.4.3 INTERSECT 与 AND 谓词 268 | 269 | 对于同一个表的两个查询结果而言,他们的交INTERSECT实际上可以等价地将两个查询的检索条件用AND谓词连接来实现。 270 | 271 | **练习题:** 272 | 273 | ****使用AND谓词查找product表中利润率高于 50%,并且售价低于 1500 的商品,查询结果如下所示。 274 | 275 | ![图片](./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 | 286 | ## 4.1.5 对称差 287 | 288 | 两个集合 A、B 的对称差是指那些仅属于A或仅属于B的元素构成的集合。对称差也是个非常基础的运算,例如,两个集合的交就可以看作是两个集合的并去掉两个集合的对称差。上述方法在其他数据库里也可以用来简单地实现表或查询结果的对称差运算: 首先使用UNION求两个表的并集,然后使用 INTERSECT 求两个表的交集,然后用并集减去交集,就得到了对称差。 289 | 290 | 但由于在 MySQL 8.0 里,由于两个表或查询结果的并不能直接求出来,因此并不适合使用上述思路来求对称差。好在还有差集运算可以使用。从直观上就能看出来,两个集合的对称差等于 `A-B` 并上 `B-A`,因此实践中可以用这个思路来求对称差。 291 | 292 | **练习题:** 293 | 294 | 使用product表和product2表的对称差来查询哪些商品只在其中一张表,结果类似于: 295 | 296 | ![图片](./img/ch04/ch04.12.png) 297 | 298 | 提示: 使用 NOT IN 实现两个表的差集。 299 | 300 | **参考答案:** 301 | 302 | ```sql 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.2 连结(JOIN) 313 | 314 | 前一节我们学习了 UNION和INTERSECT 等集合运算,这些集合运算的特征就是以行方向为单位进行操作。通俗地说,就是进行这些集合运算时,会导致记录行数的增减,使用 UNION 会增加记录行数,而使用 INTERSECT 或者 EXCEPT 会减少记录行数。 315 | 316 | 但这些运算不能改变列的变化,虽然使用函数或者 CASE表达式等列运算,可以增加列的数量,但仍然只能从一张表中提供的基础信息列中获得一些"引申列",本质上并不能提供更多的信息。如果想要从多个表获取信息,例如,如果我们想要找出某个商店里的衣服类商品的名称,数量及价格等信息,则必须分别从 shopproduct 表和 product 表获取信息。 317 | 318 | ![图片](./img/ch04/ch04.13join.png) 319 | 320 | >注: 321 | >截至目前,本书中出现的示例(除了关联子查询)基本上都是从一张表中选取数据,但实际上,期望得到的数据往往会分散在不同的表之中,这时候就需要使用连结了。 322 | >之前在学习关联子查询时我们发现,使用关联子查询也可以从其他表获取信息,但**连结**更适合从多张表获取信息。 323 | 324 | 连结(JOIN)就是使用某种关联条件(一般是使用相等判断谓词"="), 将其他表中的列添加过来,进行“添加列”的集合运算。可以说,连结是 SQL 查询的核心操作,掌握了连结,能够从两张甚至多张表中获取列,能够将过去使用关联子查询等过于复杂的查询简化为更加易读的形式,以及进行一些更加复杂的查询。 325 | 326 | SQL 中的连结有多种分类方法,我们这里使用最基础的内连结和外连结的分类方法来分别进行讲解。 327 | 328 | ## 4.2.1 内连结(INNER JOIN) 329 | 330 | 内连结的语法格式是: 331 | 332 | ```sql 333 | -- 内连结 334 | FROM INNER JOIN ON 335 | ``` 336 | 其中 INNER 关键词表示使用了内连结,至于内连结的涵义,目前暂时可以不必细究。 337 | 例如,还是刚才那个问题: 338 | 339 | 找出某个商店里的衣服类商品的名称,数量及价格等信息。 340 | 341 | 我们进一步把这个问题明确化: 342 | 343 | 找出东京商店里的衣服类商品的商品名称,商品价格,商品种类,商品数量信息。 344 | 345 | ### 4.2.1.1 使用内连结从两个表获取信息 346 | 347 | 我们先来分别观察所涉及的表,product 表保存了商品编号,商品名称,商品种类等信息,这个表可以提供关于衣服种类的衣服的详细信息,但是不能提供商店信息。 348 | 349 | ![图片](./img/ch04/ch04.14tb.png) 350 | 351 | 我们接下来观察 shopproduct 表,这个表里有商店编号名称,商店的商品编号及数量。但要想获取商品的种类及名称售价等信息,则必须借助于 product 表。 352 | 353 | ![图片](./img/ch04/ch04.15shopproduct.png) 354 | 355 | 所以问题的关键是,找出一个类似于"轴"或者"桥梁"的公共列,将两张表用这个列连结起来。这就是连结运算所要作的事情。 356 | 357 | 我们来对比一下上述两张表,可以发现,商品编号列是一个公共列,因此很自然的事情就是用这个商品编号列来作为连接的“桥梁”,将product和shopproduct这两张表连接起来。 358 | 359 | ![图片](./img/ch04/ch04.16tb73.png) 360 | 361 | >注: 362 | >如果你使用过 excel 的 vlookup 函数,你会发现这个函数正好也能够实现这个功能。实际上,在思路上,关联子查询更像是 vlookup 函数: 以表 A 为主表,然后根据表 A 的关联列的每一行的取值,逐个到表 B 中的关联列中去查找取值相等的行。 363 | >当数据量较少时,这种方式并不会有什么性能问题,但数据量较大时,这种方式将会导致较大的计算开销:对于外部查询返回的每一行数据,都会向内部的子查询传递一个关联列的值,然后内部子查询根据传入的值执行一次查询然后返回它的查询结果。这就使得,例如外部主查询的返回结果有一万行,那么子查询就会执行一万次,这将会带来非常恐怖的时间消耗。 364 | 365 | 我们把上述问题进行分解: 366 | 367 | 首先,找出每个商店的商店编号、商店名称、商品编号、商品名称、商品类别、商品售价和商品数量等信息。 368 | 369 | 按照内连结的语法,在 FROM 子句中使用 INNER JOIN 将两张表连接起来,并为 ON 子句指定连结条件为 shopproduct.product_id=product.product_id, 就得到了如下的查询语句: 370 | 371 | ```sql 372 | SELECT SP.shop_id 373 | ,SP.shop_name 374 | ,SP.product_id 375 |   ,P.product_name 376 | ,P.product_type 377 | ,P.sale_price 378 | ,SP.quantity 379 |   FROM shopproduct AS SP 380 |  INNER JOIN product AS P 381 |   ON SP.product_id = P.product_id; 382 | ``` 383 | 在上述查询中,我们分别为两张表指定了简单的别名,这种操作在使用连结时是非常常见的,通过别名会让我们在编写查询时少打很多字,并且更重要的是,会让查询语句看起来更加简洁。 384 | 上述查询将会得到如下的结果: 385 | 386 | ![图片](./img/ch04/ch04.17result.png) 387 | 388 | 观察查询结果,我们看到,这个结果里的列已经包含了所有我们需要的信息。 389 | 390 | 关于内连结,需要注意以下三点: 391 | 392 | **要点一: 进行连结时需要在 FROM 子句中使用多张表** 393 | 394 | 之前的 FROM 子句中只有一张表,而这次我们同时使用了 shopproduct 和 product 两张表,使用关键字 INNER JOIN 就可以将两张表连结在一起了: 395 | 396 | ```sql 397 | FROM shopproduct AS SP INNER JOIN product AS P 398 | ``` 399 | **要点二:必须使用 ON 子句来指定连结条件** 400 | 401 | 在进行内连结时 ON 子句是必不可少的(大家可以试试去掉上述查询的 ON 子句后会有什么结果)。 402 | 403 | ON 子句是专门用来指定连结条件的,我们在上述查询的 ON 之后指定两张表连结所使用的列以及比较条件,基本上,它能起到与 WHERE 相同的筛选作用,我们会在本章的结尾部分进一步探讨这个话题。 404 | 405 | **要点三: SELECT 子句中的列最好按照 表名.列名 的格式来使用** 406 | 407 | 当两张表的列除了用于关联的列之外,没有名称相同的列的时候,也可以不写表名,但表名使得我们能够在今后的任何时间阅读查询代码的时候,都能马上看出每一列来自于哪张表,能够节省我们很多时间。 408 | 409 | 但是,如果两张表有其他名称相同的列,则必须使用上述格式来选择列名,否则查询语句会报错。 410 | 411 | 我们回到上述查询所回答的问题。通过观察上述查询的结果,我们发现,这个结果离我们的目标:找出东京商店的衣服类商品的基础信息已经很接近了。接下来,我们只需要把这个查询结果作为一张表,给它增加一个 WHERE 子句来指定筛选条件。 412 | 413 | ### 4.2.1.2 结合 WHERE 子句使用内连结 414 | 415 | 如果需要在使用内连结的时候同时使用 WHERE 子句对检索结果进行筛选,则需要把 WHERE 子句写在 ON 子句的后边。 416 | 417 | 例如,对于上述查询问题,我们可以在前一步查询的基础上,增加 WHERE 条件。 418 | 419 | 增加 WHERE 子句的方式有好几种,我们先从最简单的说起。 420 | 421 | 第一种增加 WEHRE 子句的方式,就是把上述查询作为子查询,用括号封装起来,然后在外层查询增加筛选条件。 422 | 423 | ```sql 424 | SELECT * 425 |   FROM (-- 第一步查询的结果 426 |   SELECT SP.shop_id 427 | ,SP.shop_name 428 | ,SP.product_id 429 |   ,P.product_name 430 | ,P.product_type 431 | ,P.sale_price 432 | ,SP.quantity 433 |     FROM shopproduct AS SP 434 |   INNER JOIN product AS P 435 |   ON SP.product_id = P.product_id) AS STEP1 436 | WHERE shop_name = '东京' 437 | AND product_type = '衣服'; 438 | ``` 439 | 还记得我们学习子查询时的认识吗?子查询的结果其实也是一张表,只不过是一张虚拟的表,它并不真实存在于数据库中,只是数据库中其他表经过筛选,聚合等查询操作后得到的一个“视图”。 440 | 这种写法能很清晰地分辨出每一个操作步骤,在我们还不十分熟悉 SQL 查询每一个子句的执行顺序的时候可以帮到我们。 441 | 442 | 但实际上,如果我们熟知 WHERE 子句将在 FROM 子句之后执行,也就是说,在做完 INNER JOIN ... ON 得到一个新表后,才会执行 WHERE 子句,那么就得到标准的写法: 443 | 444 | ```sql 445 | SELECT SP.shop_id 446 | ,SP.shop_name 447 | ,SP.product_id 448 |   ,P.product_name 449 | ,P.product_type 450 | ,P.sale_price 451 | ,SP.quantity 452 |   FROM shopproduct AS SP 453 |  INNER JOIN product AS P 454 |   ON SP.product_id = P.product_id 455 |  WHERE SP.shop_name = '东京' 456 |   AND P.product_type = '衣服'; 457 | ``` 458 | 我们首先给出上述查询的执行顺序: 459 | 460 | FROM 子句 -> WHERE 子句 -> SELECT 子句 461 | 462 | 也就是说,两张表是先按照连结列进行了连结,得到了一张新表,然后 WHERE 子句对这张新表的行按照两个条件进行了筛选,最后,SELECT 子句选出了那些我们需要的列。 463 | 464 | 此外,一种不是很常见的做法是,还可以将 WHERE 子句中的条件直接添加在 ON 子句中,这时候 ON 子句后最好用括号将连结条件和筛选条件括起来。 465 | 466 | ```sql 467 | SELECT SP.shop_id 468 | ,SP.shop_name 469 | ,SP.product_id 470 |   ,P.product_name 471 | ,P.product_type 472 | ,P.sale_price 473 | ,SP.quantity 474 |   FROM shopproduct AS SP 475 |  INNER JOIN product AS P 476 |   ON (SP.product_id = P.product_id 477 |   AND SP.shop_name = '东京' 478 |   AND P.product_type = '衣服'); 479 | ``` 480 | 但上述这种把筛选条件和连结条件都放在 ON 子句的写法,不是太容易阅读,不建议大家使用。 481 | 另外,先连结再筛选的标准写法的执行顺序是,两张完整的表做了连结之后再做筛选,如果要连结多张表,或者需要做的筛选比较复杂时,在写 SQL 查询时会感觉比较吃力。在结合 WHERE 子句使用内连结的时候,我们也可以更改任务顺序,并采用任务分解的方法,先分别在两个表使用 WHERE 进行筛选,然后把上述两个子查询连结起来。 482 | 483 | ```sql 484 | SELECT SP.shop_id 485 | ,SP.shop_name 486 | ,SP.product_id 487 |   ,P.product_name 488 | ,P.product_type 489 | ,P.sale_price 490 | ,SP.quantity 491 |   FROM (-- 子查询 1:从 shopproduct 表筛选出东京商店的信息 492 |   SELECT * 493 |   FROM shopproduct 494 |   WHERE shop_name = '东京' ) AS SP 495 |  INNER JOIN -- 子查询 2:从 product 表筛选出衣服类商品的信息 496 | (SELECT * 497 |   FROM product 498 |   WHERE product_type = '衣服') AS P 499 |   ON SP.product_id = P.product_id; 500 | ``` 501 | 先分别在两张表里做筛选,把复杂的筛选条件按表分拆,然后把筛选结果(作为表)连接起来,避免了写复杂的筛选条件,因此这种看似复杂的写法,实际上整体的逻辑反而非常清晰。在写查询的过程中,首先要按照最便于自己理解的方式来写,先把问题解决了,再思考优化的问题。 502 | 503 | **练习题:** 504 | 505 | 找出每个商店里的衣服类商品的名称及价格等信息,希望得到如下结果: 506 | 507 | ![图片](./img/ch04/ch04.18result2.png) 508 | 509 | ``` 510 | -- 参考答案 1--不使用子查询 511 | SELECT SP.shop_id,SP.shop_name,SP.product_id 512 |   ,P.product_name, P.product_type, P.purchase_price 513 |   FROM shopproduct  AS SP 514 | INNER JOIN product AS P 515 | ON SP.product_id = P.product_id 516 |  WHERE P.product_type = '衣服'; 517 | ``` 518 | ``` 519 | -- 参考答案 2--使用子查询 520 | SELECT SP.shop_id, SP.shop_name, SP.product_id 521 |   ,P.product_name, P.product_type, P.purchase_price 522 |   FROM shopproduct AS SP 523 | INNER JOIN --从 product 表找出衣服类商品的信息 524 | (SELECT product_id, product_name, product_type, purchase_price 525 |      FROM product 526 |    WHERE product_type = '衣服')AS P 527 |   ON SP.product_id = P.product_id; 528 | ``` 529 | 上述第二种写法虽然包含了子查询,并且代码行数更多,但由于每一层的目的很明确,更适于阅读,并且在外连结的情形下,还能避免错误使用 WHERE 子句导致外连结失效的问题,相关示例见后文中的"结合 WHERE 子句使用外连结"章节。 530 | 531 | **练习题:** 532 | 533 | 分别使用连结两个子查询和不使用子查询的方式,找出东京商店里,售价低于 2000 的商品信息,希望得到如下结果。 534 | 535 | ![图片](./img/ch04/ch04.19result3.png) 536 | 537 | ``` 538 | -- 参考答案 539 | -- 不使用子查询 540 | SELECT SP.*, P.* 541 |   FROM shopproduct AS SP 542 |  INNER JOIN product AS P 543 |   ON SP.product_id = P.product_id 544 |  WHERE shop_id = '000A' 545 |    AND sale_price < 2000; 546 | ``` 547 | 548 | ### 4.2.1.3 结合 GROUP BY 子句使用内连结 549 | 550 | 结合 GROUP BY 子句使用内连结,需要根据分组列位于哪个表区别对待。 551 | 552 | 最简单的情形,是在内连结之前就使用 GROUP BY 子句。 553 | 554 | 但是如果分组列和被聚合的列不在同一张表,且二者都未被用于连结两张表,则只能先连结,再聚合。 555 | 556 | **练习题:** 557 | 558 | 每个商店中,售价最高的商品的售价分别是多少? 559 | 560 | ```sql 561 | -- 参考答案 562 | SELECT SP.shop_id 563 | ,SP.shop_name 564 | ,MAX(P.sale_price) AS max_price 565 |   FROM shopproduct AS SP 566 |  INNER JOIN product AS P 567 |     ON SP.product_id = P.product_id 568 |  GROUP BY SP.shop_id,SP.shop_name; 569 | ``` 570 | **思考题:** 571 | 572 | 上述查询得到了每个商品售价最高的商品,但并不知道售价最高的商品是哪一个。如何获取每个商店里售价最高的商品的名称和售价? 573 | >注: 这道题的一个简易的方式是使用下一章的窗口函数。当然,也可以使用其他我们已经学过的知识来实现。例如,在找出每个商店售价最高商品的价格后,使用这个价格再与 product 列进行连结,但这种做法在价格不唯一时会出现问题。 574 | 575 | ### 4.2.1.4 自连结(SELF JOIN) 576 | 577 | 之前的内连结,连结的都是不一样的两个表。但实际上一张表也可以与自身作连结,这种连接称之为自连结。需要注意,自连结并不是区分于内连结和外连结的第三种连结,自连结可以是外连结也可以是内连结,它是不同于内连结外连结的另一个连结的分类方法。 578 | 579 | ### 4.2.1.5 内连结与关联子查询 580 | 581 | 回忆第五章第三节关联子查询中的问题:找出每个商品种类当中售价高于该类商品的平均售价的商品。当时我们是使用关联子查询来实现的。 582 | 583 | ```sql 584 | SELECT product_type, product_name, sale_price 585 |   FROM product AS P1 586 |  WHERE sale_price > (SELECT AVG(sale_price) 587 |                       FROM product AS P2 588 |                     WHERE P1.product_type = P2.product_type 589 |                     GROUP BY product_type); 590 | ``` 591 | 使用内连结同样可以解决这个问题: 592 | 首先,使用 GROUP BY 按商品类别分类计算每类商品的平均价格。 593 | 594 | ```sql 595 | SELECT product_type 596 | ,AVG(sale_price) AS avg_price 597 | FROM product 598 | GROUP BY product_type; 599 | ``` 600 | 接下来,将上述查询与表 product 按照 product_type (商品种类)进行内连结。 601 | ``` 602 | SELECT  P1.product_id 603 | ,P1.product_name 604 |   ,P1.product_type 605 | ,P1.sale_price 606 |   ,P2.avg_price 607 | FROM product AS P1 608 | INNER JOIN 609 | (SELECT product_type,AVG(sale_price) AS avg_price 610 | FROM product 611 | GROUP BY product_type) AS P2 612 |   ON P1.product_type = P2.product_type; 613 | ``` 614 | 最后,增加 WHERE 子句,找出那些售价高于该类商品平均价格的商品。完整的代码如下: 615 | ```sql 616 | SELECT  P1.product_id 617 | ,P1.product_name 618 | ,P1.product_type 619 |   ,P1.sale_price 620 | ,P2.avg_price 621 | FROM product AS P1 622 | INNER JOIN 623 | (SELECT product_type,AVG(sale_price) AS avg_price 624 |  FROM product 625 | GROUP BY product_type) AS P2 626 |     ON P1.product_type = P2.product_type 627 | WHERE P1.sale_price > P2.avg_price; 628 | ``` 629 | 仅仅从代码量上来看,上述方法似乎比关联子查询更加复杂,但这并不意味着这些代码更难理解。通过上述分析,很容易发现上述代码的逻辑实际上更符合我们的思路,因此尽管看起来复杂,但思路实际上更加清晰。 630 | 631 | ### 4.2.1.6 自然连结(NATURAL JOIN) 632 | 633 | 自然连结并不是区别于内连结和外连结的第三种连结,它其实是内连结的一种特例--当两个表进行自然连结时,会按照两个表中都包含的列名来进行等值内连结,此时无需使用 ON 来指定连接条件。 634 | 635 | ```sql 636 | SELECT * FROM shopproduct NATURAL JOIN product 637 | ``` 638 | 上述查询得到的结果,会把两个表的公共列(这里是 product_id,可以有多个公共列)放在第一列,然后按照两个表的顺序和表中列的顺序,将两个表中的其他列都罗列出来。 639 | 640 | ![图片](./img/ch04/ch04.20.png) 641 | 642 | **练习题:** 643 | 644 | 试写出与上述自然连结等价的内连结。 645 | 646 | ```sql 647 | -- 参考答案 648 | SELECT SP.product_id,SP.shop_id,SP.shop_name,SP.quantity 649 |   ,P.product_name,P.product_type,P.sale_price 650 |   ,P.purchase_price,P.regist_date   651 |   FROM shopproduct AS SP 652 |  INNER JOIN product AS P 653 |   ON SP.product_id = P.product_id; 654 | ``` 655 | 使用自然连结还可以求出两张表或子查询的公共部分,例如教材中 7-1 选取表中公共部分--INTERSECT 一节中的问题:求表 product 和表 product2 中的公共部分,也可以用自然连结来实现: 656 | 657 | ```sql 658 | SELECT * FROM product NATURAL JOIN product2; 659 | ``` 660 | 661 | ![图片](./img/ch04/ch04.21.png) 662 | 663 | 这个结果和书上给的结果并不一致,少了运动 T 恤,这是由于运动 T 恤的 regist_date 字段为空,在进行自然连结时,来自于 product 和 product2 的运动 T 恤这一行数据在进行比较时,实际上是在逐字段进行等值连结,回忆我们在 `3.4.4 ISNULL,IS NOT NULL` 这一节学到的缺失值的比较方法就可得知,两个缺失值用等号进行比较,结果不为真。而连结只会返回对连结条件返回为真的那些行。 664 | 665 | 如果我们将查询语句进行修改: 666 | 667 | ```sql 668 | SELECT * 669 |   FROM (SELECT product_id, product_name 670 |           FROM product ) AS A  671 | NATURAL JOIN  672 | (SELECT product_id, product_name 673 |   FROM product2) AS B; 674 | ``` 675 | 那就可以得到正确的结果了: 676 | 677 | ![图片](./img/ch04/ch04.22.png) 678 | 679 | ### 4.2.1.7 使用连结求交集 680 | 681 | 我们在上一节表的加减法里知道,MySQL 8.0 里没有交集运算,我们当时是通过并集和差集来实现求交集的。现在学了联结, 让我们试试使用连结来实现求交集的运算。 682 | 683 | 练习题: 使用内连结求 product 表和 product2 表的交集。 684 | 685 | ```sql 686 | SELECT P1.* 687 | FROM product AS P1 688 |  INNER JOIN product2 AS P2 689 |   ON (P1.product_id = P2.product_id 690 |   AND P1.product_name = P2.product_name 691 |   AND P1.product_type = P2.product_type 692 |   AND P1.sale_price = P2.sale_price 693 |   AND P1.regist_date = P2.regist_date); 694 | ``` 695 | 得到如下结果 696 | 697 | ![图片](./img/ch04/ch04.23.png) 698 | 699 | 注意上述结果和 P230 的结果并不一致--少了 product_id='0003'这一行,观察源表数据可发现,少的这行数据的 regist_date 为缺失值,回忆第六章讲到的 IS NULL 谓词,我们得知,这是由于缺失值是不能用等号进行比较导致的。 700 | 701 | 如果我们仅仅用 product_id 来进行连结: 702 | 703 | ```sql 704 | SELECT P1.* 705 | FROM product AS P1 706 |  INNER JOIN product2 AS P2 707 |   ON P1.product_id = P2.product_id; 708 | ``` 709 | 查询结果: 710 | 711 | ![图片](./img/ch04/ch04.24.png) 712 | 713 | 这次就一致了。 714 | 715 | ## 4.2.2 外连结(OUTER JOIN) 716 | 717 | 内连结会丢弃两张表中不满足 ON 条件的行,和内连结相对的就是外连结。外连结会根据外连结的种类有选择地保留无法匹配到的行。 718 | 719 | 按照保留的行位于哪张表,外连结有三种形式:左连结,右连结和全外连结。 720 | 721 | 左连结会保存左表中无法按照 ON 子句匹配到的行,此时对应右表的行均为缺失值;右连结则会保存右表中无法按照 ON 子句匹配到的行,此时对应左表的行均为缺失值;而全外连结则会同时保存两个表中无法按照 ON子句匹配到的行,相应的另一张表中的行用缺失值填充。 722 | 723 | 三种外连结的对应语法分别为: 724 | 725 | ```sql 726 | -- 左连结 727 | FROM LEFT OUTER JOIN ON 728 | -- 右连结 729 | FROM RIGHT OUTER JOIN ON 730 | -- 全外连结 731 | FROM FULL OUTER JOIN ON 732 | ``` 733 | 734 | ### 4.2.2.1 左连结与右连结 735 | 736 | 由于连结时可以交换左表和右表的位置,因此左连结和右连结并没有本质区别。接下来我们先以左连结为例进行学习。所有的内容在调换两个表的前后位置,并将左连结改为右连结之后,都能得到相同的结果。稍后再介绍全外连结的概念。 737 | 738 | ### 4.2.2.2 使用左连结从两个表获取信息 739 | 740 | 如果你仔细观察过将 `shopproduct` 和 `product` 进行内连结前后的结果的话,你就会发现,`product` 表中有两种商品并未在内连结的结果里,就是说,这两种商品并未在任何商店有售(这通常意味着比较重要的业务信息,例如,这两种商品在所有商店都处于缺货状态, 需要及时补货)。现在,让我们先把之前内连结的 SELECT 语句转换为左连结试试看吧。 741 | 742 | 练习题:统计每种商品分别在哪些商店有售,需要包括那些在每个商店都没货的商品。 743 | 744 | 使用左连结的代码如下(注意区别于书上的右连结): 745 | 746 | ```sql 747 | SELECT SP.shop_id 748 | ,SP.shop_name 749 | ,SP.product_id 750 |   ,P.product_name 751 | ,P.sale_price 752 |   FROM product AS P 753 |   LEFT OUTER JOIN shopproduct AS SP 754 |   ON SP.product_id = P.product_id; 755 | ``` 756 | 上述查询得到的检索结果如下(由于并未使用 ORDER BY 子句指定顺序,你执行上述代码得到的结果可能顺序与下图不同): 757 | 758 | ![图片](./img/ch04/ch04.25.png) 759 | 760 | 我们观察上述结果可以发现,有两种商品:高压锅和圆珠笔,在所有商店都没有销售。由于我们在 SELECT 子句选择列的显示顺序以及未对结果进行排序的原因,这个事实需要你仔细地进行观察。 761 | 762 | **● 外连结要点 1:选取出单张表中全部的信息** 763 | 764 | 与内连结的结果相比,不同点显而易见,那就是结果的行数不一样。内连结的结果中有 13 条记录,而外连结的结果中有 15 条记录,增加的 2 条记录到底是什么呢?这正是外连结的关键点。多出的 2 条记录是高压锅和圆珠笔,这 2 条记录在 shopproduct 表中并不存在,也就是说,这 2 种商品在任何商店中都没有销售。由于内连结只能选取出同时存在于两张表中的数据,因此只在 product 表中存在的 2 种商品并没有出现在结果之中。相反,对于外连结来说,只要数据存在于某一张表当中,就能够读取出来。在实际的业务中,例如想要生成固定行数的单据时,就需要使用外连结。如果使用内连结的话,根据 SELECT 语句执行时商店库存状况的不同,结果的行数也会发生改变,生成的单据的版式也会受到影响,而使用外连结能够得到固定行数的结果。虽说如此,那些表中不存在的信息我们还是无法得到,结果中高压锅和圆珠笔的商店编号和商店名称都是 NULL (具体信息大家都不知道,真是无可奈何)。外连结名称的由来也跟 NULL 有关,即“结果中包含原表中不存在(在原表之外)的信息”。相反,只包含表内信息的连结也就被称为内连结了。 765 | 766 | **● 外连结要点 2:使用 LEFT、RIGHT 来指定主表.** 767 | 768 | 外连结还有一点非常重要,那就是要把哪张表作为主表。最终的结果中会包含主表内所有的数据。指定主表的关键字是 LEFT 和 RIGHT。顾名思义,使用 LEFT 时 FROM 子句中写在左侧的表是主表,使用 RIGHT 时右侧的表是主表。代码清单 7-11 中使用了 RIGHT ,因此,右侧的表,也就是 product 表是主表。我们还可以像代码清单 7-12 这样进行改写,意思完全相同。这样你可能会困惑,到底应该使用 LEFT 还是 RIGHT?其实它们的功能没有任何区别,使用哪一个都可以。通常使用 LEFT 的情况会多一些,但也并没有非使用这个不可的理由,使用 RIGHT 也没有问题。 769 | 770 | 通过交换两个表的顺序,同时将 LEFT 更换为 RIGHT(如果原先是 RIGHT,则更换为 LEFT),两种方式会到完全相同的结果。 771 | 772 | ### 4.2.2.3 结合 WHERE 子句使用左连结 773 | 774 | 上一小节我们学到了外连结的基础用法,并且在上一节也学习了结合WHERE子句使用内连结的方法,但在结合WHERE子句使用外连结时,由于外连结的结果很可能与内连结的结果不一样,会包含那些主表中无法匹配到的行,并用缺失值填写另一表中的列,由于这些行的存在,因此在外连结时使用WHERE子句,情况会有些不一样。我们来看一个例子: 775 | 776 | **练习题:** 777 | 778 | 使用外连结从shopproduct表和product表中找出那些在某个商店库存少于50的商品及对应的商店。希望得到如下结果。 779 | 780 | ![图片](./img/ch04/ch04.26.png) 781 | 782 | 注意高压锅和圆珠笔两种商品在所有商店都无货,所以也应该包括在内。 783 | 784 | 按照“结合WHERE子句使用内连结”的思路,我们很自然会写出如下代码 785 | 786 | ```sql 787 | SELECT P.product_id 788 | ,P.product_name 789 | ,P.sale_price 790 |   ,SP.shop_id 791 | ,SP.shop_name 792 | ,SP.quantity 793 |   FROM product AS P 794 |   LEFT OUTER JOIN shopproduct AS SP 795 |   ON SP.product_id = P.product_id 796 |  WHERE quantity< 50; 797 | ``` 798 | 然而不幸的是,得到的却是如下的结果: 799 | 800 | ![图片](./img/ch04/ch04.27.png) 801 | 802 | 观察发现,少了在所有商店都无货的高压锅和圆珠笔。聪明的你可能很容易想到,在WHERE过滤条件中增加 **`OR quantity IS NULL`** 的条件,便可以得到预期的结果。然而在真实的查询环境中,由于数据量大且数据质量并非设想的那样"干净",我们并不能容易地意识到缺失值等问题数据的存在,因此,还是让我们想一下如何改写我们的查询以使得它能够适应更复杂的真实数据的情形吧。 803 | 804 | 联系到我们已经掌握了的SQL查询的执行顺序(FROM->WHERE->SELECT),我们发现,问题可能出在筛选条件上,因为在进行完外连结后才会执行WHERE子句,因此那些主表中无法被匹配到的行就被WHERE条件筛选掉了。 805 | 806 | 明白了这一点,我们就可以试着把WHERE子句挪到外连结之前进行:先写个子查询,用来从shopproduct表中筛选quantity<50的商品,然后再把这个子查询和主表连结起来。 807 | 808 | 我们把上述思路写成SQL查询语句: 809 | 810 | ```sql 811 | SELECT P.product_id 812 | ,P.product_name 813 | ,P.sale_price 814 | ,SP.shop_id 815 | ,SP.shop_name 816 | ,SP.quantity 817 |   FROM product AS P 818 |   LEFT OUTER JOIN-- 先筛选quantity<50的商品 819 | (SELECT * 820 |   FROM shopproduct 821 |   WHERE quantity < 50 ) AS SP 822 |   ON SP.product_id = P.product_id; 823 | ``` 824 | 得到的结果如下: 825 | 826 | ![图片](./img/ch04/ch04.28.png) 827 | 828 | ### 4.2.2.4 在 MySQL 中实现全外连结 829 | 830 | 有了对左连结和右连结的了解,就不难理解全外连结的含义了。全外连结本质上就是对左表和右表的所有行都予以保留,能用 ON 关联到的就把左表和右表的内容在一行内显示,不能被关联到的就分别显示,然后把多余的列用缺失值填充。 831 | 832 | 遗憾的是,MySQL8.0 目前还不支持全外连结,不过我们可以对左连结和右连结的结果进行 UNION 来实现全外连结。 833 | 834 | ## 4.2.3 多表连结 835 | 836 | 通常连结只涉及 2 张表,但有时也会出现必须同时连结 3 张以上的表的情况,原则上连结表的数量并没有限制。 837 | 838 | ### 4.2.3.1 多表进行内连结 839 | 840 | 首先创建一个用于三表连结的表 Inventoryproduct。首先我们创建一张用来管理库存商品的表,假设商品都保存在 P001 和 P002 这 2 个仓库之中。 841 | 842 | ![图片](./img/ch04/ch04.29.png) 843 | 844 | 建表语句如下: 845 | 846 | ``` 847 | CREATE TABLE Inventoryproduct 848 | ( inventory_id CHAR(4) NOT NULL, 849 | product_id CHAR(4) NOT NULL, 850 | inventory_quantity INTEGER NOT NULL, 851 | PRIMARY KEY (inventory_id, product_id)); 852 | ``` 853 | 然后插入一些数据: 854 | ``` 855 | --- DML:插入数据 856 | START TRANSACTION; 857 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 858 | VALUES ('P001', '0001', 0); 859 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 860 | VALUES ('P001', '0002', 120); 861 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 862 | VALUES ('P001', '0003', 200); 863 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 864 | VALUES ('P001', '0004', 3); 865 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 866 | VALUES ('P001', '0005', 0); 867 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 868 | VALUES ('P001', '0006', 99); 869 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 870 | VALUES ('P001', '0007', 999); 871 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 872 | VALUES ('P001', '0008', 200); 873 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 874 | VALUES ('P002', '0001', 10); 875 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 876 | VALUES ('P002', '0002', 25); 877 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 878 | VALUES ('P002', '0003', 34); 879 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 880 | VALUES ('P002', '0004', 19); 881 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 882 | VALUES ('P002', '0005', 99); 883 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 884 | VALUES ('P002', '0006', 0); 885 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 886 | VALUES ('P002', '0007', 0 ); 887 | INSERT INTO Inventoryproduct (inventory_id, product_id, inventory_quantity) 888 | VALUES ('P002', '0008', 18); 889 | COMMIT; 890 | ``` 891 | 接下来,我们根据上表及 shopproduct 表和 product 表,使用内连接找出每个商店都有那些商品,每种商品的库存总量分别是多少。 892 | ``` 893 | SELECT SP.shop_id 894 | ,SP.shop_name 895 | ,SP.product_id 896 |   ,P.product_name 897 | ,P.sale_price 898 | ,IP.inventory_quantity 899 |   FROM shopproduct AS SP 900 |  INNER JOIN product AS P 901 |   ON SP.product_id = P.product_id 902 | INNER JOIN Inventoryproduct AS IP 903 |   ON SP.product_id = IP.product_id 904 |  WHERE IP.inventory_id = 'P001'; 905 | ``` 906 | 得到如下结果 907 | 908 | ![图片](./img/ch04/ch04.30.png) 909 | 910 | 我们可以看到,连结第三张表的时候,也是通过 ON 子句指定连结条件(这里使用最基础的等号将作为连结条件的 product 表和 shopproduct 表中的商品编号 product _id 连结了起来),由于 product 表和 shopproduct 表已经进行了连结,因此就无需再对 product 表和 Inventoryproduct 表进行连结了(虽然也可以进行连结,但结果并不会发生改变,因为本质上并没有增加新的限制条件)。 911 | 912 | 即使想要把连结的表增加到 4 张、5 张……使用 INNER JOIN 进行添加的方式也是完全相同的。 913 | 914 | ### 4.2.3.2 多表进行外连结 915 | 916 | 正如之前所学发现的,外连结一般能比内连结有更多的行,从而能够比内连结给出更多关于主表的信息,多表连结的时候使用外连结也有同样的作用。 917 | 918 | 例如, 919 | 920 | ```sql 921 | SELECT P.product_id 922 | ,P.product_name 923 | ,P.sale_price 924 |   ,SP.shop_id 925 | ,SP.shop_name 926 | ,IP.inventory_quantity 927 |   FROM product AS P 928 | LEFT OUTER JOIN shopproduct AS SP 929 | ON SP.product_id = P.product_id 930 | LEFT OUTER JOIN Inventoryproduct AS IP 931 | ON SP.product_id = IP.product_id; 932 | ``` 933 | 查询结果 934 | 935 | ![图片](./img/ch04/ch04.31.png) 936 | 937 | ## 4.2.4 ON 子句进阶--非等值连结 938 | 939 | 在刚开始介绍连结的时候,书上提到过,除了使用相等判断的等值连结,也可以使用比较运算符来进行连接。实际上,包括比较运算符(<、<=、>、>=、BETWEEN)和谓词运算(LIKE、IN、NOT 等等)在内的所有的逻辑运算都可以放在 ON 子句内作为连结条件。 940 | 941 | ### 4.2.4.1 非等值自左连结(SELF JOIN) 942 | 943 | 使用非等值自左连结实现排名。 944 | 945 | **练习题:** 946 | 947 | 希望对 product 表中的商品按照售价赋予排名。一个从集合论出发,使用自左连结的思路是,对每一种商品,找出售价不低于它的所有商品,然后对售价不低于它的商品使用 COUNT 函数计数。例如,对于价格最高的商品, 948 | 949 | ```sql 950 | SELECT product_id 951 | ,product_name 952 | ,sale_price 953 | ,COUNT(p2_id) AS my_rank 954 | FROM (--使用自左连结对每种商品找出价格不低于它的商品 955 |   SELECT P1.product_id 956 |   ,P1.product_name 957 |   ,P1.sale_price 958 |   ,P2.product_id AS P2_id 959 |   ,P2.product_name AS P2_name 960 |   ,P2.sale_price AS P2_price  961 |   FROM product AS P1 962 |    LEFT OUTER JOIN product AS P2  963 |  ON P1.sale_price <= P2.sale_price  964 | ) AS X 965 | GROUP BY product_id, product_name, sale_price 966 | ORDER BY my_rank;  967 | ``` 968 | 注 1:COUNT 函数的参数是列名时,会忽略该列中的缺失值,参数为 * 时则不忽略缺失值。 969 | 注 2:上述排名方案存在一些问题--如果两个商品的价格相等,则会导致两个商品的排名错误,例如,叉子和打孔器的排名应该都是第六,但上述查询导致二者排名都是第七。试修改上述查询使得二者的排名均为第六。 970 | 971 | ![图片](./img/ch04/ch04.32.png) 972 | 973 | 注 3:实际上,进行排名有专门的函数,这是 MySQL 8.0 新增加的窗口函数中的一种(窗口函数将在下一章学习),但在较低版本的 MySQL 中只能使用上述自左连结的思路。 974 | 975 | 使用非等值自左连结进行累计求和: 976 | 977 | **练习题:** 978 | 979 | 请按照商品的售价从低到高,对售价进行累计求和[注:这个案例缺少实际意义, 并且由于有两种商品价格相同导致了不必要的复杂度, 但示例数据库的表结构比较简单, 暂时未想出有实际意义的例题] 980 | 981 | 首先,按照题意,对每种商品使用自左连结,找出比该商品售价价格更低或相等的商品 982 | 983 | ```sql 984 | SELECT P1.product_id 985 | ,P1.product_name 986 | ,P1.sale_price 987 |   ,P2.product_id AS P2_id 988 | ,P2.product_name AS P2_name 989 |   ,P2.sale_price AS P2_price 990 | FROM product AS P1 991 | LEFT OUTER JOIN product AS P2 992 | ON P1.sale_price >= P2.sale_price 993 | ORDER BY P1.sale_price,P1.product_id; 994 | ``` 995 | 查看查询结果 996 | 997 | ![图片](./img/ch04/ch04.33.png) 998 | 999 | 看起来似乎没什么问题。 1000 | 1001 | 下一步,按照 P1.product_Id 分组,对 P2_price 求和: 1002 | 1003 | ```sql 1004 | SELECT product_id 1005 | ,product_name 1006 |   ,sale_price 1007 | ,SUM(P2_price) AS cum_price 1008 | FROM (SELECT  P1.product_id 1009 | ,P1.product_name 1010 | ,P1.sale_price 1011 | ,P2.product_id AS P2_id 1012 | ,P2.product_name AS P2_name 1013 | ,P2.sale_price AS P2_price  1014 |   FROM product AS P1 1015 | LEFT OUTER JOIN product AS P2 1016 | ON P1.sale_price >= P2.sale_price 1017 | ORDER BY P1.sale_price,P1.product_id ) AS X 1018 | GROUP BY product_id, product_name, sale_price 1019 | ORDER BY sale_price,product_id; 1020 | ``` 1021 | 得到的查询结果为: 1022 | 1023 | ![图片](./img/ch04/ch04.34.png) 1024 | 1025 | 观察上述查询结果发现,由于有两种商品的售价相同,在使用 >= 进行连结时,导致了累计求和错误,这是由于这两种商品售价相同导致的。因此实际上之前是不应该单独只用 >= 作为连结条件的。考察我们建立自左连结的本意,是要找出满足:①比该商品售价更低的,或者是 ②该种商品自身,以及 ③如果 A 和 B 两种商品售价相等,则建立连结时,如果 P1.A 和 P2.A、P2.B 建立了连接,则 P1.B 不再和 P2.A 建立连结,因此根据上述约束条件,利用 ID 的有序性,进一步将上述查询改写为: 1026 | 1027 | ```sql 1028 | SELECT product_id, product_name, sale_price 1029 |   ,SUM(P2_price) AS cum_price  1030 |   FROM 1031 |   (SELECT P1.product_id, P1.product_name, P1.sale_price 1032 |         ,P2.product_id AS P2_id 1033 |   ,P2.product_name AS P2_name 1034 |   ,P2.sale_price AS P2_price  1035 |     FROM product AS P1 1036 |   LEFT OUTER JOIN product AS P2 1037 |   ON ((P1.sale_price > P2.sale_price) 1038 |              OR (P1.sale_price = P2.sale_price 1039 |   AND P1.product_id<=P2.product_id)) 1040 | ORDER BY P1.sale_price,P1.product_id) AS X 1041 |  GROUP BY product_id, product_name, sale_price 1042 |  ORDER BY sale_price,cum_price; 1043 | ``` 1044 | 这次结果就正确了。 1045 | 1046 | ![图片](./img/ch04/ch04.35.png) 1047 | 1048 | ## 4.2.5 交叉连结—— CROSS JOIN(笛卡尔积) 1049 | 1050 | 之前的无论是外连结内连结,一个共同的必备条件就是连结条件--ON 子句,用来指定连结的条件。如果你试过不使用这个连结条件的连结查询,你可能已经发现,结果会有很多行。在连结去掉 ON 子句,就是所谓的交叉连结(CROSS JOIN),交叉连结又叫笛卡尔积,后者是一个数学术语。两个集合做笛卡尔积,就是使用集合 A 中的每一个元素与集合 B 中的每一个元素组成一个有序的组合。数据库表(或者子查询)的并,交和差都是在纵向上对表进行扩张或筛选限制等运算的, 这要求表的列数及对应位置的列的数据类型"相容",因此这些运算并不会增加新的列,而交叉连接(笛卡尔积)则是在横向上对表进行扩张,即增加新的列,这一点和连结的功能是一致的。但因为没有了ON子句的限制,会对左表和右表的每一行进行组合,这经常会导致很多无意义的行出现在检索结果中。当然,在某些查询需求中,交叉连结也有一些用处。 1051 | 1052 | 交叉连结的语法有如下几种形式: 1053 | 1054 | ```sql 1055 | -- 1.使用关键字 CROSS JOIN 显式地进行交叉连结 1056 | SELECT SP.shop_id 1057 | ,SP.shop_name 1058 | ,SP.product_id 1059 |   ,P.product_name 1060 | ,P.sale_price 1061 | FROM shopproduct AS SP 1062 |  CROSS JOIN product AS P; 1063 | --2.使用逗号分隔两个表,并省略 ON 子句 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 , product AS P; 1070 | ``` 1071 | 请大家试着执行一下以上语句。 1072 | 可能大家会惊讶于结果的行数,但我们还是先来介绍一下语法结构吧。对满足相同规则的表进行交叉连结的集合运算符是 CROSS JOIN (笛卡儿积)。进行交叉连结时无法使用内连结和外连结中所使用的ON 子句,这是因为交叉连结是对两张表中的全部记录进行交叉组合,因此结果中的记录数通常是两张表中行数的乘积。本例中,因为 shopproduct 表存在 13 条记录,product 表存在 8 条记录,所以结果中就包含了 13 × 8 = 104 条记录。 1073 | 1074 | 可能这时会有读者想起前面我们提到过集合运算中的乘法会在本节中进行详细学习,这就是上面介绍的交叉连结。内连结是交叉连结的一部分,“内”也可以理解为“包含在交叉连结结果中的部分”。相反,外连结的“外”可以理解为“交叉连结结果之外的部分”。 1075 | 1076 | 交叉连结没有应用到实际业务之中的原因有两个。一是其结果没有实用价值,二是由于其结果行数太多,需要花费大量的运算时间和高性能设备的支持。 1077 | 1078 | ### 4.2.5.1 [扩展阅读]连结与笛卡儿积的关系 1079 | 1080 | 考察笛卡儿积和连结,不难发现,笛卡儿积可以视作一种特殊的连结(事实上笛卡儿积的语法也可以写作 CROSS JOIN),这种连结的 ON 子句是一个恒为真的谓词。 1081 | 1082 | 反过来思考,在对笛卡儿积进行适当的限制之后,也就得到了内连结和外连结。 1083 | 1084 | 例如,对于 shopproduct 表和 product 表,首先建立笛卡尔乘积: 1085 | 1086 | ``` 1087 | SELECT SP.*, P.* 1088 | FROM shopproduct AS SP 1089 | CROSS JOIN product AS P; 1090 | ``` 1091 | 查询结果的一部分如下: 1092 | 1093 | ![图片](./img/ch04/ch04.36.png) 1094 | 1095 | 然后对上述笛卡尔乘积增加筛选条件 SP.product_id=P.product_id,就得到了和内连结一致的结果: 1096 | 1097 | ``` 1098 | SELECT SP.*, P.* 1099 | FROM shopproduct AS SP 1100 | CROSS JOIN product AS P 1101 | WHERE SP.product_id = P.product_id; 1102 | ``` 1103 | 查询结果如下: 1104 | 1105 | ![图片](./img/ch04/ch04.37.png) 1106 | 1107 | 实际上,正如书中所说,上述写法中,将 CROSS JOIN 改为逗号后,正是内连结的旧式写法,但在 ANSI 和 ISO 的 SQL-92 标准中,已经将使用 INNER JOIN ..ON.. 的写法规定为标准写法,因此极力推荐大家在平时写 SQL 查询时,使用规范写法。 1108 | 1109 | ## 4.2.6 连结的特定语法和过时语法 1110 | 1111 | 在笛卡尔积的基础上,我们增加一个 WHERE 子句,将之前的连结条件作为筛选条件加进去,我们会发现,得到的结果恰好是直接使用内连接的结果。 1112 | 1113 | 试执行以下查询,并将查询结果与内连结一节第一个例子的结果做对比。 1114 | 1115 | ```sql 1116 | SELECT SP.shop_id 1117 | ,SP.shop_name 1118 | ,SP.product_id 1119 | ,P.product_name 1120 | ,P.sale_price 1121 |   FROM shopproduct AS SP 1122 |  CROSS JOIN product AS P 1123 |  WHERE SP.product_id = P.product_id; 1124 | ``` 1125 | 我们发现,这两个语句得到的结果是相同的。 1126 | 之前我们学习的内连结和外连结的语法都符合标准 SQL 的规定,可以在所有 DBMS 中执行,因此大家可以放心使用。但是如果大家之后从事系统开发工作,或者阅读遗留 SQL 查询语句的话,一定会碰到需要阅读他人写的代码并进行维护的情况,而那些使用特定和过时语法的程序就会成为我们的麻烦。 1127 | 1128 | SQL 是一门特定语法及过时语法非常多的语言,虽然之前本书中也多次提及,但连结是其中特定语法的部分,现在还有不少年长的程序员和系统工程师仍在使用这些特定的语法。例如,将本节最初介绍的内连结的 SELECT 语句替换为过时语法的结果如下所示。 1129 | 1130 | 使用过时语法的内连结(结果与代码清单 7-9 相同) 1131 | 1132 | ```sql 1133 | SELECT SP.shop_id 1134 | ,SP.shop_name 1135 | ,SP.product_id 1136 | ,P.product_name 1137 | ,P.sale_price 1138 | FROM shopproduct SP, product P 1139 | WHERE SP.product_id = P.product_id 1140 | AND SP.shop_id = '000A'; 1141 | ``` 1142 | 这样的书写方式所得到的结果与标准语法完全相同,并且这样的语法可以在所有的 DBMS 中执行,并不能算是特定的语法,只是过时了而已。 1143 | 但是,由于这样的语法不仅过时,而且还存在很多其他的问题,因此不推荐大家使用,理由主要有以下三点: 1144 | 1145 | 第一,使用这样的语法无法马上判断出到底是内连结还是外连结(又或者是其他种类的连结)。 1146 | 1147 | 第二,由于连结条件都写在 WHERE 子句之中,因此无法在短时间内分辨出哪部分是连结条件,哪部分是用来选取记录的限制条件。 1148 | 1149 | 第三,我们不知道这样的语法到底还能使用多久。每个 DBMS 的开发者都会考虑放弃过时的语法,转而支持新的语法。虽然并不是马上就不能使用了,但那一天总会到来的。 1150 | 1151 | 虽然这么说,但是现在使用这些过时语法编写的程序还有很多,到目前为止还都能正常执行。我想大家很可能会碰到这样的代码,因此还是希望大家能够了解这些知识。 1152 | 1153 | # 练习题(请给出代码、包含代码及代码执行结果的截图) 1154 | 1155 | # **4.1** 1156 | 1157 | 找出 product 和 product2 中售价高于 500 的商品的基本信息。 1158 | 1159 | # **4.2** 1160 | 1161 | 借助对称差的实现方式,求product和product2的交集。 1162 | 1163 | # **4.3** 1164 | 1165 | 每类商品中售价最高的商品都在哪些商店有售 ? 1166 | 1167 | # **4.4** 1168 | 1169 | 分别使用内连结和关联子查询每一类商品中售价最高的商品。 1170 | 1171 | # **4.5** 1172 | 1173 | 用关联子查询实现:在 product 表中,取出 product_id、product_name、sale_price,并按照商品的售价从低到高进行排序,对售价进行累计求和。 1174 | -------------------------------------------------------------------------------- /ch05_SQL高级处理.md: -------------------------------------------------------------------------------- 1 | # 第五章:SQL高级处理 2 | 3 | ## 5.1 窗口函数 4 | 5 | ### 5.1.1 窗口函数概念及基本的使用方法 6 | 7 | 窗口函数也称为**OLAP函数**。OLAP 是 `OnLine AnalyticalProcessing` 的简称,意思是对数据库数据进行实时分析处理。 8 | 9 | 为了便于理解,称之为 `窗口函数`。常规的SELECT语句都是对整张表进行查询,而窗口函数可以让我们有选择的去某一部分数据进行汇总、计算和排序。 10 | 11 | 窗口函数的通用形式: 12 | 13 | ```sql 14 | <窗口函数> OVER ([ PARTITION BY <列名> ] 15 | [ ORDER BY <排序用列名> ])   16 | ``` 17 | [ ]中的内容可以省略。 18 | 19 | 窗口函数最关键的是搞明白关键字 **PARTITON BY** 和 **ORDER BY** 的作用。 20 | 21 | **PARTITON BY 子句** 可选参数,指示如何将查询行划分为组,类似于 GROUP BY 子句的分组功能,但是 PARTITION BY 子句并不具备 GROUP BY 子句的汇总功能,并不会改变原始表中记录的行数。 22 | 23 | **ORDER BY 子句** 可选参数,指示如何对每个分区中的行进行排序,即决定窗口内,是按那种规则(字段)来排序的。 24 | 25 | **注意** 26 | 27 | 虽然 **PARTITON BY 子句** 和 **ORDER BY 子句** 都是可选参数,但是两个参数不能同时没有(最少二选一)。不然, `<窗口函数> OVER( )` 这种用法没用实际意义(窗口由所有查询行组成,窗口函数使用所有行计算结果)。 28 | 29 | 举个栗子: 30 | 31 | ```sql 32 | SELECT product_name 33 | ,product_type 34 | ,sale_price 35 | ,RANK() OVER (PARTITION BY product_type 36 | ORDER BY sale_price) AS ranking 37 | FROM product;   38 | ``` 39 | 40 | 得到的结果是: 41 | 42 | ![图片](./img/ch05/ch0501.png) 43 | 44 | 我们先忽略生成的新列 - [ranking], 看下原始数据在PARTITION BY 和 ORDER BY 关键字的作用下发生了什么变化。 45 | 46 | PARTITION BY 能够设定窗口对象范围。本例中,为了按照商品种类进行排序,我们指定了product_type。即一个商品种类就是一个小的"窗口"。 47 | 48 | ORDER BY 能够指定按照哪一列、何种顺序进行排序。为了按照销售单价的升序进行排列,我们指定了sale_price。此外,窗口函数中的ORDER BY与SELECT语句末尾的ORDER BY一样,可以通过关键字ASC/DESC来指定升序/降序。省略该关键字时会默认按照ASC,也就是 49 | 50 | 升序进行排序。本例中就省略了上述关键字 。 51 | 52 | 53 | ![图片](./img/ch05/ch0502.png) 54 | 55 | 56 | 57 | ## 5.2 窗口函数种类 58 | 59 | 大致来说,窗口函数可以分为两类。 60 | 61 | 一是 将SUM、MAX、MIN等聚合函数用在窗口函数中 62 | 63 | 二是 RANK、DENSE_RANK等排序用的专用窗口函数 64 | 65 | ### 5.2.1 专用窗口函数 66 | 67 | **RANK函数** 68 | 69 | 计算排序时,如果存在相同位次的记录,则会跳过之后的位次。 70 | 71 | 例)有 3 条记录排在第 1 位时:1 位、1 位、1 位、4 位…… 72 | 73 | **DENSE_RANK函数** 74 | 75 | 同样是计算排序,即使存在相同位次的记录,也不会跳过之后的位次。 76 | 77 | 例)有 3 条记录排在第 1 位时:1 位、1 位、1 位、2 位…… 78 | 79 | **ROW_NUMBER函数** 80 | 81 | 赋予唯一的连续位次。 82 | 83 | 例)有 3 条记录排在第 1 位时:1 位、2 位、3 位、4 位 84 | 85 | 运行以下代码: 86 | 87 | ```sql 88 | SELECT product_name 89 | ,product_type 90 | ,sale_price 91 | ,RANK() OVER (ORDER BY sale_price) AS ranking 92 | ,DENSE_RANK() OVER (ORDER BY sale_price) AS dense_ranking 93 | ,ROW_NUMBER() OVER (ORDER BY sale_price) AS row_num 94 | FROM product;   95 | ``` 96 | 97 | ![图片](./img/ch05/ch0503.png) 98 | 99 | 100 | ### 5.2.2 聚合函数在窗口函数上的使用 101 | 102 | 聚合函数在窗口函数中的使用方法和之前的专用窗口函数一样,只是出来的结果是一个**累计**的聚合函数值。 103 | 104 | 运行以下代码: 105 | 106 | ```sql 107 | SELECT product_id 108 | ,product_name 109 | ,sale_price 110 | ,SUM(sale_price) OVER (ORDER BY product_id) AS current_sum 111 | ,AVG(sale_price) OVER (ORDER BY product_id) AS current_avg   112 | FROM product;   113 | ``` 114 | 115 | ![图片](./img/ch05/ch0504.png) 116 | 117 | ![图片](./img/ch05/ch0505.png) 118 | 119 | 可以看出,聚合函数结果是,按我们指定的排序,这里是product_id,**当前所在行及之前所有的行**的合计或均值。即累计到当前行的聚合。 120 | 121 | ## 5.3 窗口函数的的应用 - 计算移动平均 122 | 123 | 在上面提到,聚合函数在窗口函数使用时,计算的是累积到当前行的所有的数据的聚合。 实际上,还可以指定更加详细的**汇总范围**。该汇总范围称为 **框架** (frame)。 124 | 125 | 语法 126 | 127 | ```sql 128 | <窗口函数> OVER (ORDER BY <排序用列名> 129 | ROWS n PRECEDING )   130 | 131 | <窗口函数> OVER (ORDER BY <排序用列名> 132 | ROWS BETWEEN n PRECEDING AND n FOLLOWING) 133 | ``` 134 | PRECEDING(“之前”), 将框架指定为 “截止到之前 n 行”,加上自身行 135 | 136 | FOLLOWING(“之后”), 将框架指定为 “截止到之后 n 行”,加上自身行 137 | 138 | 执行以下代码: 139 | 140 | ```sql 141 | SELECT product_id 142 | ,product_name 143 | ,sale_price 144 | ,AVG(sale_price) OVER (ORDER BY product_id 145 | ROWS 2 PRECEDING) AS moving_avg 146 | FROM product;   147 | ``` 148 | 149 | **执行结果1:** 150 | 151 | 注意观察框架的范围。 152 | 153 | ![图片](./img/ch05/ch0506.png) 154 | 155 | BETWEEN 1 PRECEDING AND 1 FOLLOWING,将框架指定为 “之前1行” + “之后1行” + “自身” 156 | 157 | 执行以下代码: 158 | 159 | ```sql 160 | SELECT product_id 161 | ,product_name 162 | ,sale_price 163 | ,AVG(sale_price) OVER (ORDER BY product_id 164 | ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS moving_avg 165 | FROM product;   166 | ``` 167 | 168 | **执行结果2:** 169 | 170 | 注意观察框架的范围。 171 | 172 | ![图片](./img/ch05/ch0507.png) 173 | 174 | ### 5.3.1 窗口函数适用范围和注意事项 175 | 176 | * 原则上,窗口函数只能在SELECT子句中使用。 177 | * 窗口函数OVER 中的ORDER BY 子句并不会影响最终结果的排序。其只是用来决定窗口函数按何种顺序计算。 178 | ## 5.4 GROUPING运算符 179 | 180 | ### 5.4.1 ROLLUP - 计算合计及小计 181 | 182 | 常规的GROUP BY 只能得到每个分类的小计,有时候还需要计算分类的合计,可以用 ROLLUP关键字。 183 | 184 | ```sql 185 | SELECT product_type 186 | ,regist_date 187 | ,SUM(sale_price) AS sum_price 188 | FROM product 189 | GROUP BY product_type, regist_date WITH ROLLUP;   190 | ``` 191 | 得到的结果为: 192 | 193 | ![图片](./img/ch05/ch0508.png) 194 | 195 | ![图片](./img/ch05/ch0509.png) 196 | 197 | 这里ROLLUP 对product_type, regist_date两列进行合计汇总。结果实际上有三层聚合,如下图 模块3是常规的 GROUP BY 的结果,需要注意的是衣服 有个注册日期为空的,这是本来数据就存在日期为空的,不是对衣服类别的合计; 模块2和1是 ROLLUP 带来的合计,模块2是对产品种类的合计,模块1是对全部数据的总计。 198 | 199 | ROLLUP 可以对多列进行汇总求小计和合计。 200 | 201 | ![图片](./img/ch05/ch0510.png) 202 | 203 | ## 5.5 存储过程和函数 204 | 205 | ### 5.5.1 基本介绍 206 | 207 | 基本语法: 208 | ```sql 209 | [delimiter //]($$,可以是其他特殊字符) 210 | CREATE 211 | [DEFINER = user] 212 | PROCEDURE sp_name ([proc_parameter[,...]]) 213 | [characteristic ...] 214 | [BEGIN] 215 | routine_body1; 216 | 217 | routine_body2; 218 | [END//]($$,可以是其他特殊字符) 219 | ``` 220 | 这些语句被用来创建一个存储例程(一个存储过程或函数)。也就是说,指定的例程被服务器知道了。默认情况下,一个存储例程与默认数据库相关联。要将该例程明确地与一个给定的数据库相关联,需要在创建该例程时将其名称指定为 `db_name.sp_name`。 221 | 222 | 使用 `CALL` 语句调用一个存储过程。而要调用一个存储的函数时,则要在表达式中引用它。在表达式计算期间,该函数返回一个值。 223 | 224 | `routine_body` 由一个有效的SQL例程语句组成。它可以是一个简单的语句 **(通常以分号 `;` 结尾)**, 如 `SELECT` 或 `INSERT`,或一个使用 `BEGIN` 和 `END` 编写的复合语句。复合语句可以包含声明、循环和其他控制结构语句。在实践中,存储函数倾向于使用复合语句,除非例程主体由一个 `RETURN` 语句组成。 225 | 226 | 另外,你可能注意到了,这里特别提到了特殊分隔符 // 或者 $$。那么,他们是必须使用的吗?答案是否定的,只有在你使用命令行模式创建存储过程时,必须使用特殊分隔符来与分号进行区分,因为 SQL 语句的默认分隔符是分号,而存储过程通常包含多条 SQL 语句,每条语句都以分号结尾。如果不修改分隔符,SQL 语句在执行时遇到第一个分号时,认为当前语句已经结束,进而尝试执行它,从而无法完整创建包含 BEGIN ... END 块的存储过程,导致创建失败。 227 | 228 | 当你使用 SQL 客户端来创建存储过程时,不存在这个问题,无需修改分隔符。 229 | 230 | ### 5.5.2 参数介绍 231 | 232 | 存储过程和函数的参数有三类,分别是:`IN`,`OUT`,`INOUT`,其中: 233 | - `IN` 是入参。每个参数默认都是一个 `IN` 参数。如需设定一个参数为其他类型参数,请在参数名称前使用关键字 `OUT` 或 `INOUT` 。一个IN参数将一个值传递给一个过程。存储过程可能会修改这个值,但是当存储过程返回时,调用者不会看到这个修改。 234 | - `OUT` 是出参。一个 `OUT` 参数将一个值从过程中传回给调用者。它的初始值在过程中是 `NULL` ,当过程返回时,调用者可以看到它的值。 235 | - `INOUT` :一个 `INOUT` 参数由调用者初始化,可以被存储过程修改,当存储过程返回时,调用者可以看到存储过程的任何改变。 236 | 237 | 对于每个 `OUT` 或 `INOUT` 参数,在调用过程的 `CALL` 语句中传递一个用户定义的变量,以便在过程返回时可以获得其值。如果你是在另一个存储过程或函数中调用存储过程,你也可以将一个常规参数或本地常规变量作为 `OUT` 或 `INOUT` 参数传递。如果从一个触发器中调用存储过程,也可以将 `NEW.col_name` 作为一个 `OUT` 或 `INOUT` 参数传递。 238 | 239 | ### 5.5.2 应用示例 240 | 241 | - 查询 242 | 下面的示例显示了一个简单的存储过程,给定一个国家代码,计算在 `world` 数据库的城市表中出现的该国家的城市数量。使用 `IN` 参数传递国家代码,使用 `OUT` 参数返回城市计数: 243 | ```sql 244 | -- 命令行执行模式 245 | DELIMITER // 246 | 247 | DROP PROCEDURE IF EXISTS citycount // 248 | 249 | CREATE PROCEDURE citycount (IN country CHAR(3), OUT cities INT) 250 | BEGIN 251 | SELECT COUNT(*) INTO cities FROM world.city 252 | WHERE CountryCode = country; 253 | END// 254 | 255 | DELIMITER ; 256 | 257 | CALL citycount('CHN', @cities); -- cities in China 258 | 259 | SELECT @cities; 260 | ``` 261 | 262 | - 创建表 263 | ```SQL 264 | -- 命令行执行模式 265 | use world; 266 | 267 | DELIMITER $$ 268 | 269 | CREATE DEFINER=`root`@`localhost` PROCEDURE `product_test`() 270 | BEGIN 271 | #Routine body goes here... 272 | CREATE TABLE product_test like shop.product; 273 | END$$ 274 | 275 | DELIMITER; 276 | 277 | call `product_test`(); 278 | 279 | show tables; 280 | ``` 281 | - 插入数据 282 | ```SQL 283 | -- 使用 SQL 客户端进行创建 284 | -- 按照不同维度来汇总每日销售数据,分别插入相应的统计表 285 | 286 | CREATE PROCEDURE `P_SALES_STATISTICS`(IN SDATE VARCHAR(20)) 287 | BEGIN 288 | DELETE FROM shop.sales_statistics_1 WHERE sdate = SDATE; 289 | INSERT INTO shop.sales_statistics_1 290 | SELECT sdate, product_id, product_name, SUM(sales_quantity) AS sales_quantity, SUM(sales_amount) AS sales_amount 291 | FROM shop.sales_record 292 | GROUP BY sdate, product_id, product_name; 293 | 294 | DELETE FROM shop.sales_statistics_2 WHERE sdate = SDATE; 295 | INSERT INTO shop.sales_statistics_2 296 | SELECT a.sdate, b.product_type, SUM(a.sales_quantity) AS sales_quantity, SUM(a.sales_amount) AS sales_amount 297 | FROM shop.sales_record a 298 | LEFT JOIN shop.product b 299 | ON a.product_id = b.product_id 300 | GROUP BY a.sdate, b.product_type; 301 | END 302 | ``` 303 | 304 | ## 5.6 预处理声明 PREPARE Statement 305 | 306 | MySQL 从4.1版本开始引入了 `PREPARE Statement` 特性,使用 `client/server binary protocol` 代替 `textual protocol`,其将包含占位符 () 的查询传递给 MySQL 服务器,如以下示例所示: 307 | ```sql 308 | SELECT * 309 | FROM products 310 | WHERE productCode = ?; 311 | ``` 312 | 当MySQL使用不同的 `productCode` 值执行此查询时,它不必完全解析查询。因此,这有助于MySQL更快地执行查询,特别是当MySQL多次执行相同的查询时。productcode 313 | 314 | 由于预准备语句使用占位符 (),这有助于避免 SQL 注入的许多变体,从而使应用程序更安全。 315 | 316 | 基本语法: 317 | ```sql 318 | PREPARE stmt_name FROM preparable_stmt 319 | ``` 320 | 321 | ### 5.6.1 使用步骤 322 | 323 | `MySQL PREPARE Statement` 使用步骤如下: 324 | 325 | 1. PREPARE – 准备需要执行的语句预处理声明。 326 | 2. EXECUTE – 执行预处理声明。 327 | 3. DEALLOCATE PREPARE – 释放预处理声明。 328 | 329 | 下图说明了预处理声明的使用过程: 330 | 331 | ![图片](./img/ch05/ch0511MySQL-Prepared-Statement.png) 332 | 333 | ### 5.6.2 使用示例 334 | 335 | 这里使用 `shop` 中的 `product` 表进行演示。 336 | 337 | 首先,定义预处理声明如下: 338 | ```sql 339 | PREPARE stmt1 FROM 340 | 'SELECT 341 | product_id, 342 | product_name 343 | FROM product 344 | WHERE product_id = ?'; 345 | ``` 346 | 其次,声明变量 `pcid`,代表商品编号,并将其值设置为 `0005`: 347 | ```sql 348 | SET @pcid = '0005'; 349 | ``` 350 | 第三,执行预处理声明: 351 | ```sql 352 | EXECUTE stmt1 USING @pcid; 353 | ``` 354 | ![图片](./img/ch05/ch0512-prepare-result1.png) 355 | 356 | 第四,为变量 `pcid` 分配另外一个商品编号: 357 | ```sql 358 | SET @pcid = '0008'; 359 | ``` 360 | 第五,使用新的商品编号执行预处理声明: 361 | ```sql 362 | EXECUTE stmt1 USING @pcid; 363 | ``` 364 | ![图片](./img/ch05/ch0513-prepare-result2.png) 365 | 366 | 最后,释放预处理声明以释放其占用的资源: 367 | ```sql 368 | DEALLOCATE PREPARE stmt1; 369 | ``` 370 | 371 | ### 练习题(请给出代码、包含代码及代码执行结果的截图) 372 | 373 | #### **5.1** 374 | 375 | 请说出针对本章中使用的 product(商品)表执行如下 SELECT 语句所能得到的结果。 376 | 377 | ```sql 378 | SELECT product_id 379 | ,product_name 380 | ,sale_price 381 | ,MAX(sale_price) OVER (ORDER BY product_id) AS Current_max_price 382 | FROM product; 383 | ``` 384 | #### **5.2** 385 | 386 | 继续使用product表,计算出按照登记日期(regist_date)升序进行排列的各日期的销售单价(sale_price)的总额。排序是需要将登记日期为NULL 的“运动 T 恤”记录排在第 1 位(也就是将其看作比其他日期都早) 387 | 388 | #### **5.3** 389 | 390 | 思考题 391 | 392 | ① 窗口函数不指定PARTITION BY的效果是什么? 393 | 394 | ② 为什么说窗口函数只能在SELECT子句中使用?实际上,在ORDER BY 子句使用系统并不会报错。 395 | 396 | #### **5.4** 397 | 398 | 使用存储过程创建20个与 `shop.product` 表结构相同的表,如下图所示: 399 | 400 | ![图片](./img/ch05/ch0514-question5.4v2.png) 401 | 402 | 403 | 404 | -------------------------------------------------------------------------------- /ch06_决胜秋招.md: -------------------------------------------------------------------------------- 1 | # 第六章:决胜秋招 2 | 3 | **(请给出代码、包含代码及代码执行结果的截图)** 4 | 5 | ### 要求必须提供作业链接(不要求全部做完),不提供的视为水卡 6 | 7 | ### [决胜秋招-建表语句](https://github.com/datawhalechina/wonderful-sql/blob/main/materials/create_table_sql/%E5%86%B3%E8%83%9C%E7%A7%8B%E6%8B%9B-%E5%BB%BA%E8%A1%A8%E8%AF%AD%E5%8F%A5.sql) 8 | 9 | ## Section A 10 | 11 | ### 练习一: 分数排名(难度:中等) 12 | 13 | 假设在某次期末考试中,二年级四个班的平均成绩分别是 `93、93、93、91`。 14 | 15 | ```plain 16 | +-------+-----------+ 17 | | class | score_avg | 18 | +-------+-----------+ 19 | | 1 | 93 | 20 | | 2 | 93 | 21 | | 3 | 93 | 22 | | 4 | 91 | 23 | +-------+-----------+ 24 | ``` 25 | 目前有如下三种排序结果,请根据查询结果书写出查询用 sql 26 | 27 | ```plain 28 | +-------+-----------+-------+-------+-------+ 29 | | class | score_avg | rank1 | rank2 | rank3 | 30 | +-------+-----------+-------+-------+-------+ 31 | | 1 | 93 | 1 | 1 | 1 | 32 | | 2 | 93 | 1 | 1 | 2 | 33 | | 3 | 93 | 1 | 1 | 3 | 34 | | 4 | 91 | 4 | 2 | 4 | 35 | +-------+-----------+-------+-------+-------+ 36 | ``` 37 | 38 | ## Section B 39 | 40 | ### 练习一:行转列 41 | 假设 A B C 三位小朋友期末考试成绩如下所示: 42 | ```plain 43 | +-----+-----------+------| 44 | | name| subject |score | 45 | +-----+-----------+------| 46 | | A | chinese | 99 | 47 | | A | math | 98 | 48 | | A | english | 97 | 49 | | B | chinese | 92 | 50 | | B | math | 91 | 51 | | B | english | 90 | 52 | | C | chinese | 88 | 53 | | C | math | 87 | 54 | | C | english | 86 | 55 | +-----+-----------+------| 56 | ``` 57 | 请使用 SQL 代码将以上成绩转换为如下格式: 58 | ```plain 59 | +-----+-----------+------|---------| 60 | | name| chinese | math | english | 61 | +-----+-----------+------|---------| 62 | | A | 99 | 98 | 97 | 63 | | B | 92 | 91 | 90 | 64 | | C | 88 | 87 | 86 | 65 | +-----+-----------+------|---------| 66 | ``` 67 | 68 | ### 练习二:列转行 69 | 假设 A B C 三位小朋友期末考试成绩如下所示: 70 | ```plain 71 | +-----+-----------+------|---------| 72 | | name| chinese | math | english | 73 | +-----+-----------+------|---------| 74 | | A | 99 | 98 | 97 | 75 | | B | 92 | 91 | 90 | 76 | | C | 88 | 87 | 86 | 77 | +-----+-----------+------|---------| 78 | ``` 79 | 请使用 SQL 代码将以上成绩转换为如下格式: 80 | ```plain 81 | +-----+-----------+------| 82 | | name| subject |score | 83 | +-----+-----------+------| 84 | | A | chinese | 99 | 85 | | A | math | 98 | 86 | | A | english | 97 | 87 | | B | chinese | 92 | 88 | | B | math | 91 | 89 | | B | english | 90 | 90 | | C | chinese | 88 | 91 | | C | math | 87 | 92 | | C | english | 86 | 93 | +-----+-----------+------| 94 | ``` 95 | ### 练习三:谁是明星带货主播? 96 | 假设,某平台2021年主播带货销售额日统计数据如下: 97 | 98 | 表名 `anchor_sales` 99 | ```plain 100 | +-------------+------------+---------| 101 | | anchor_name | date | sales | 102 | +-------------+------------+---------| 103 | | A | 20210101 | 40000 | 104 | | B | 20210101 | 80000 | 105 | | A | 20210102 | 10000 | 106 | | C | 20210102 | 90000 | 107 | | A | 20210103 | 7500 | 108 | | C | 20210103 | 80000 | 109 | +-------------+------------+---------| 110 | ``` 111 | 定义:如果某主播的某日销售额占比达到该平台当日销售总额的 90% 及以上,则称该主播为明星主播,当天也称为明星主播日。 112 | 113 | 请使用 SQL 完成如下计算: 114 | 115 | a. 2021年有多少个明星主播日? 116 | 117 | b. 2021年有多少个明星主播? 118 | 119 | ### 练习四:MySQL 中如何查看sql语句的执行计划?可以看到哪些信息? 120 | 121 | ### 练习五:解释一下 SQL 数据库中 ACID 是指什么 122 | 123 | ## Section C 124 | 125 | ### 练习一:行转列 126 | 127 | 假设有如下比赛结果: 128 | 129 | ```plain 130 | +--------------+-----------+ 131 | | cdate | result | 132 | +--------------+-----------+ 133 | | 2021-01-01 | 胜 | 134 | | 2021-01-01 | 胜 | 135 | | 2021-01-01 | 负 | 136 | | 2021-01-03 | 胜 | 137 | | 2021-01-03 | 负 | 138 | | 2021-01-03 | 负 | 139 | +------------+-------------+ 140 | ``` 141 | 142 | 请使用 SQL 将比赛结果转换为如下形式: 143 | 144 | ```plain 145 | +--------------+-----+-----| 146 | | 比赛日期 | 胜 | 负 | 147 | +--------------+-----------+ 148 | | 2021-01-01 | 2 | 1 | 149 | | 2021-01-03 | 1 | 2 | 150 | +------------+-----------+ 151 | ``` 152 | ### 练习二:列转行 153 | 154 | 假设有如下比赛结果: 155 | 156 | ```plain 157 | +--------------+-----+-----| 158 | | 比赛日期 | 胜 | 负 | 159 | +--------------+-----------+ 160 | | 2021-01-01 | 4 | 1 | 161 | | 2021-01-03 | 1 | 4 | 162 | +------------+-----------+ 163 | ``` 164 | 165 | 请使用 SQL 将比赛结果转换为如下形式: 166 | 167 | ```plain 168 | +--------------+-----------+ 169 | | cdate | result | 170 | +--------------+-----------+ 171 | | 2021-01-01 | 胜 | 172 | | 2021-01-01 | 胜 | 173 | | 2021-01-01 | 胜 | 174 | | 2021-01-01 | 胜 | 175 | | 2021-01-01 | 负 | 176 | | 2021-01-03 | 胜 | 177 | | 2021-01-03 | 负 | 178 | | 2021-01-03 | 负 | 179 | | 2021-01-03 | 负 | 180 | | 2021-01-03 | 负 | 181 | +------------+-------------+ 182 | ``` 183 | 184 | ### 练习三:连续登录 185 | 186 | 有用户表行为记录表t_act_records表,包含两个字段:uid(用户ID),imp_date(日期) 187 | 188 | 1. 计算2021年每个月,每个用户连续登录的最多天数 189 | 2. 计算2021年每个月,连续2天都有登录的用户名单 190 | 3. 计算2021年每个月,连续5天都有登录的用户数 191 | 192 | 构造表mysql如下: 193 | ```sql 194 | DROP TABLE if EXISTS t_act_records; 195 | CREATE TABLE t_act_records 196 | (uid VARCHAR(20), 197 | imp_date DATE); 198 | 199 | INSERT INTO t_act_records VALUES('u1001', 20210101); 200 | INSERT INTO t_act_records VALUES('u1002', 20210101); 201 | INSERT INTO t_act_records VALUES('u1003', 20210101); 202 | INSERT INTO t_act_records VALUES('u1003', 20210102); 203 | INSERT INTO t_act_records VALUES('u1004', 20210101); 204 | INSERT INTO t_act_records VALUES('u1004', 20210102); 205 | INSERT INTO t_act_records VALUES('u1004', 20210103); 206 | INSERT INTO t_act_records VALUES('u1004', 20210104); 207 | INSERT INTO t_act_records VALUES('u1004', 20210105); 208 | ``` 209 | 210 | ## 练习四:用户购买商品推荐 211 | 212 | 假设现在需要根据算法给每个 `user_id` 推荐购买商品,推荐算法比较简单,推荐和他相似的用户购买过的 `product` 即可,说明如下: 213 | - 排除用户自己购买过的商品 214 | - 相似用户定义:曾经购买过 2 种或 2 种以上的相同的商品 215 | 216 | 输入表:`orders` 217 | ```plain 218 | +---------+------------+ 219 | | user_id | product_id | 220 | +---------+------------+ 221 | | 123 | 1 | 222 | | 123 | 2 | 223 | | 123 | 3 | 224 | | 456 | 1 | 225 | | 456 | 2 | 226 | | 456 | 4 | 227 | +---------+------------+ 228 | ``` 229 | 230 | 输出表: 231 | ```plain 232 | +---------+------------+ 233 | | user_id | product_id | 234 | +---------+------------+ 235 | | 123 | 4 | 236 | | 456 | 3 | 237 | +---------+------------+ 238 | ``` 239 | 240 | ### 练习五:LEFT JOIN 是否可能会出现多出的行?为什么? 241 | 242 | 假设 t1 表有6行(关联列 name 有2行为空),t2 表有6行(关联列 name 有3行为空), 243 | 244 | 那么 `SELECT * FROM t1 LEFT JOIN t2 on t1.name = t2.name` 会返回多少行结果? 245 | 246 | 可以参考下图 247 | 248 | t1 表: 249 | ![图片](./img/Question_C/C05A.jpg) 250 | t2 表: 251 | ![图片](./img/Question_C/C05B.jpg) 252 | 253 | ### 写一写本次组队学习的收获。 254 | 255 | 如果本教程对你有帮助的话,欢迎 `star` ~~ 256 | 257 | -------------------------------------------------------------------------------- /img/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/00 SQL基础课程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/00 SQL基础课程.png -------------------------------------------------------------------------------- /img/Question_C/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/Question_C/C05A.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/Question_C/C05A.jpg -------------------------------------------------------------------------------- /img/Question_C/C05B.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/Question_C/C05B.jpg -------------------------------------------------------------------------------- /img/ch00/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch00/ch0001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0001.png -------------------------------------------------------------------------------- /img/ch00/ch0002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0002.png -------------------------------------------------------------------------------- /img/ch00/ch0003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0003.png -------------------------------------------------------------------------------- /img/ch00/ch0004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0004.png -------------------------------------------------------------------------------- /img/ch00/ch0005-mysql-install-custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0005-mysql-install-custom.png -------------------------------------------------------------------------------- /img/ch00/ch0005-mysql-install-custom2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0005-mysql-install-custom2.png -------------------------------------------------------------------------------- /img/ch00/ch0005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0005.png -------------------------------------------------------------------------------- /img/ch00/ch0005A.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0005A.png -------------------------------------------------------------------------------- /img/ch00/ch0005B.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0005B.png -------------------------------------------------------------------------------- /img/ch00/ch0005C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0005C.png -------------------------------------------------------------------------------- /img/ch00/ch0006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0006.png -------------------------------------------------------------------------------- /img/ch00/ch0007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0007.png -------------------------------------------------------------------------------- /img/ch00/ch0008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0008.png -------------------------------------------------------------------------------- /img/ch00/ch0009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0009.png -------------------------------------------------------------------------------- /img/ch00/ch0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0010.png -------------------------------------------------------------------------------- /img/ch00/ch0011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0011.png -------------------------------------------------------------------------------- /img/ch00/ch0012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0012.png -------------------------------------------------------------------------------- /img/ch00/ch0013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0013.png -------------------------------------------------------------------------------- /img/ch00/ch0014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0014.png -------------------------------------------------------------------------------- /img/ch00/ch0015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0015.png -------------------------------------------------------------------------------- /img/ch00/ch0016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0016.png -------------------------------------------------------------------------------- /img/ch00/ch0017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0017.png -------------------------------------------------------------------------------- /img/ch00/ch0018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0018.png -------------------------------------------------------------------------------- /img/ch00/ch0019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0019.png -------------------------------------------------------------------------------- /img/ch00/ch0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0020.png -------------------------------------------------------------------------------- /img/ch00/ch0021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0021.png -------------------------------------------------------------------------------- /img/ch00/ch0022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0022.png -------------------------------------------------------------------------------- /img/ch00/ch0023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0023.png -------------------------------------------------------------------------------- /img/ch00/ch0024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0024.png -------------------------------------------------------------------------------- /img/ch00/ch0025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0025.png -------------------------------------------------------------------------------- /img/ch00/ch0026.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0026.png -------------------------------------------------------------------------------- /img/ch00/ch0027.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0027.png -------------------------------------------------------------------------------- /img/ch00/ch0028.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0028.png -------------------------------------------------------------------------------- /img/ch00/ch0029.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0029.png -------------------------------------------------------------------------------- /img/ch00/ch0030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0030.png -------------------------------------------------------------------------------- /img/ch00/ch0031.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0031.png -------------------------------------------------------------------------------- /img/ch00/ch0032.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0032.png -------------------------------------------------------------------------------- /img/ch00/ch0033.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0033.png -------------------------------------------------------------------------------- /img/ch00/ch0034.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0034.png -------------------------------------------------------------------------------- /img/ch00/ch0035.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0035.png -------------------------------------------------------------------------------- /img/ch00/ch0036.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0036.png -------------------------------------------------------------------------------- /img/ch00/ch0037.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0037.png -------------------------------------------------------------------------------- /img/ch00/ch0038.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0038.png -------------------------------------------------------------------------------- /img/ch00/ch0039.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0039.png -------------------------------------------------------------------------------- /img/ch00/ch0040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0040.png -------------------------------------------------------------------------------- /img/ch00/ch0041.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0041.png -------------------------------------------------------------------------------- /img/ch00/ch0042.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0042.png -------------------------------------------------------------------------------- /img/ch00/ch0043.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0043.png -------------------------------------------------------------------------------- /img/ch00/ch0044.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0044.png -------------------------------------------------------------------------------- /img/ch00/ch0045.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0045.png -------------------------------------------------------------------------------- /img/ch00/ch0046.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0046.png -------------------------------------------------------------------------------- /img/ch00/ch0047.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0047.png -------------------------------------------------------------------------------- /img/ch00/ch0048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0048.png -------------------------------------------------------------------------------- /img/ch00/ch0049.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0049.png -------------------------------------------------------------------------------- /img/ch00/ch0050.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0050.png -------------------------------------------------------------------------------- /img/ch00/ch0051.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0051.png -------------------------------------------------------------------------------- /img/ch00/ch0052.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0052.png -------------------------------------------------------------------------------- /img/ch00/ch0053.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0053.png -------------------------------------------------------------------------------- /img/ch00/ch0054.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0054.png -------------------------------------------------------------------------------- /img/ch00/ch00541.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch00541.png -------------------------------------------------------------------------------- /img/ch00/ch0055.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0055.png -------------------------------------------------------------------------------- /img/ch00/ch0056.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0056.png -------------------------------------------------------------------------------- /img/ch00/ch0057.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0057.png -------------------------------------------------------------------------------- /img/ch00/ch0058.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0058.png -------------------------------------------------------------------------------- /img/ch00/ch0059.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0059.png -------------------------------------------------------------------------------- /img/ch00/ch0060.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0060.png -------------------------------------------------------------------------------- /img/ch00/ch0061.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0061.png -------------------------------------------------------------------------------- /img/ch00/ch0062.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0062.png -------------------------------------------------------------------------------- /img/ch00/ch0063.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0063.png -------------------------------------------------------------------------------- /img/ch00/ch0064.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0064.png -------------------------------------------------------------------------------- /img/ch00/ch0065.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0065.png -------------------------------------------------------------------------------- /img/ch00/ch0066.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0066.png -------------------------------------------------------------------------------- /img/ch00/ch0067.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0067.png -------------------------------------------------------------------------------- /img/ch00/ch0068.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0068.png -------------------------------------------------------------------------------- /img/ch00/ch0069.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0069.png -------------------------------------------------------------------------------- /img/ch00/ch0070.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0070.png -------------------------------------------------------------------------------- /img/ch00/ch0071.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0071.png -------------------------------------------------------------------------------- /img/ch00/ch0072.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0072.png -------------------------------------------------------------------------------- /img/ch00/ch0073.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0073.png -------------------------------------------------------------------------------- /img/ch00/ch0074.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0074.png -------------------------------------------------------------------------------- /img/ch00/ch0075.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ch0075.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-1.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-2.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-3.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-4.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-5.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-6.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-7.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-8.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-9.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-a.png -------------------------------------------------------------------------------- /img/ch00/ubuntu-mysql-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch00/ubuntu-mysql-b.png -------------------------------------------------------------------------------- /img/ch01/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch01/ch01.01系统结构.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch01/ch01.01系统结构.jpg -------------------------------------------------------------------------------- /img/ch01/ch01.02表的示例.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch01/ch01.02表的示例.jpg -------------------------------------------------------------------------------- /img/ch01/ch01.03商品表和列名对应关系.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch01/ch01.03商品表和列名对应关系.png -------------------------------------------------------------------------------- /img/ch01/ch01.04习题1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch01/ch01.04习题1.png -------------------------------------------------------------------------------- /img/ch02/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch02/ch02.00-not-230.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.00-not-230.png -------------------------------------------------------------------------------- /img/ch02/ch02.00-not-231.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.00-not-231.png -------------------------------------------------------------------------------- /img/ch02/ch02.01and.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.01and.png -------------------------------------------------------------------------------- /img/ch02/ch02.02or.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.02or.png -------------------------------------------------------------------------------- /img/ch02/ch02.03true.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.03true.png -------------------------------------------------------------------------------- /img/ch02/ch02.04true2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.04true2.png -------------------------------------------------------------------------------- /img/ch02/ch02.05true3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.05true3.png -------------------------------------------------------------------------------- /img/ch02/ch02.06cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.06cut.png -------------------------------------------------------------------------------- /img/ch02/ch02.07_null_first1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.07_null_first1.jpg -------------------------------------------------------------------------------- /img/ch02/ch02.07_null_first2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.07_null_first2.jpg -------------------------------------------------------------------------------- /img/ch02/ch02.07_null_first3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.07_null_first3.jpg -------------------------------------------------------------------------------- /img/ch02/ch02.07_null_first4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.07_null_first4.jpg -------------------------------------------------------------------------------- /img/ch02/ch02.07_null_last1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.07_null_last1.jpg -------------------------------------------------------------------------------- /img/ch02/ch02.07_null_last2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.07_null_last2.jpg -------------------------------------------------------------------------------- /img/ch02/ch02.07_null_last3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.07_null_last3.jpg -------------------------------------------------------------------------------- /img/ch02/ch02.07_null_last4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.07_null_last4.jpg -------------------------------------------------------------------------------- /img/ch02/ch02.07groupby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.07groupby.png -------------------------------------------------------------------------------- /img/ch02/ch02.08test26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.08test26.png -------------------------------------------------------------------------------- /img/ch02/ch02.09test27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch02/ch02.09test27.png -------------------------------------------------------------------------------- /img/ch03/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch03/ch03.01view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.01view.png -------------------------------------------------------------------------------- /img/ch03/ch03.02view2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.02view2.png -------------------------------------------------------------------------------- /img/ch03/ch03.03view3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.03view3.png -------------------------------------------------------------------------------- /img/ch03/ch03.04view4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.04view4.png -------------------------------------------------------------------------------- /img/ch03/ch03.05result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.05result.png -------------------------------------------------------------------------------- /img/ch03/ch03.06productsum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.06productsum.png -------------------------------------------------------------------------------- /img/ch03/ch03.07productsum2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.07productsum2.png -------------------------------------------------------------------------------- /img/ch03/ch03.08productsumsrc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.08productsumsrc.png -------------------------------------------------------------------------------- /img/ch03/ch03.09case.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.09case.png -------------------------------------------------------------------------------- /img/ch03/ch03.10-1-sale_price_avg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.10-1-sale_price_avg.png -------------------------------------------------------------------------------- /img/ch03/ch03.10-2-sale_price_avg_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.10-2-sale_price_avg_type.png -------------------------------------------------------------------------------- /img/ch03/ch03.10function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.10function.png -------------------------------------------------------------------------------- /img/ch03/ch03.11casewhen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.11casewhen1.png -------------------------------------------------------------------------------- /img/ch03/ch03.12casewhen2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch03/ch03.12casewhen2.png -------------------------------------------------------------------------------- /img/ch04/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch04/ch04.01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.01.png -------------------------------------------------------------------------------- /img/ch04/ch04.02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.02.png -------------------------------------------------------------------------------- /img/ch04/ch04.03union.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.03union.png -------------------------------------------------------------------------------- /img/ch04/ch04.04result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.04result.png -------------------------------------------------------------------------------- /img/ch04/ch04.05result2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.05result2.png -------------------------------------------------------------------------------- /img/ch04/ch04.05result2_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.05result2_new.png -------------------------------------------------------------------------------- /img/ch04/ch04.06result3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.06result3.png -------------------------------------------------------------------------------- /img/ch04/ch04.07result4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.07result4.png -------------------------------------------------------------------------------- /img/ch04/ch04.08result5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.08result5.png -------------------------------------------------------------------------------- /img/ch04/ch04.09except.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.09except.png -------------------------------------------------------------------------------- /img/ch04/ch04.10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.10.png -------------------------------------------------------------------------------- /img/ch04/ch04.11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.11.png -------------------------------------------------------------------------------- /img/ch04/ch04.12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.12.png -------------------------------------------------------------------------------- /img/ch04/ch04.13join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.13join.png -------------------------------------------------------------------------------- /img/ch04/ch04.14tb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.14tb.png -------------------------------------------------------------------------------- /img/ch04/ch04.15shopproduct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.15shopproduct.png -------------------------------------------------------------------------------- /img/ch04/ch04.16tb73.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.16tb73.png -------------------------------------------------------------------------------- /img/ch04/ch04.17result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.17result.png -------------------------------------------------------------------------------- /img/ch04/ch04.18result2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.18result2.png -------------------------------------------------------------------------------- /img/ch04/ch04.19result3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.19result3.png -------------------------------------------------------------------------------- /img/ch04/ch04.20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.20.png -------------------------------------------------------------------------------- /img/ch04/ch04.21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.21.png -------------------------------------------------------------------------------- /img/ch04/ch04.22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.22.png -------------------------------------------------------------------------------- /img/ch04/ch04.23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.23.png -------------------------------------------------------------------------------- /img/ch04/ch04.24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.24.png -------------------------------------------------------------------------------- /img/ch04/ch04.25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.25.png -------------------------------------------------------------------------------- /img/ch04/ch04.26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.26.png -------------------------------------------------------------------------------- /img/ch04/ch04.27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.27.png -------------------------------------------------------------------------------- /img/ch04/ch04.28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.28.png -------------------------------------------------------------------------------- /img/ch04/ch04.29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.29.png -------------------------------------------------------------------------------- /img/ch04/ch04.30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.30.png -------------------------------------------------------------------------------- /img/ch04/ch04.31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.31.png -------------------------------------------------------------------------------- /img/ch04/ch04.32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.32.png -------------------------------------------------------------------------------- /img/ch04/ch04.33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.33.png -------------------------------------------------------------------------------- /img/ch04/ch04.34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.34.png -------------------------------------------------------------------------------- /img/ch04/ch04.35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.35.png -------------------------------------------------------------------------------- /img/ch04/ch04.36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.36.png -------------------------------------------------------------------------------- /img/ch04/ch04.37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch04/ch04.37.png -------------------------------------------------------------------------------- /img/ch05/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/ch05/ch0501.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0501.png -------------------------------------------------------------------------------- /img/ch05/ch0502.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0502.png -------------------------------------------------------------------------------- /img/ch05/ch0503.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0503.png -------------------------------------------------------------------------------- /img/ch05/ch0504.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0504.png -------------------------------------------------------------------------------- /img/ch05/ch0505.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0505.png -------------------------------------------------------------------------------- /img/ch05/ch0506.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0506.png -------------------------------------------------------------------------------- /img/ch05/ch0507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0507.png -------------------------------------------------------------------------------- /img/ch05/ch0508.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0508.png -------------------------------------------------------------------------------- /img/ch05/ch0509.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0509.png -------------------------------------------------------------------------------- /img/ch05/ch0510.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0510.png -------------------------------------------------------------------------------- /img/ch05/ch0511MySQL-Prepared-Statement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0511MySQL-Prepared-Statement.png -------------------------------------------------------------------------------- /img/ch05/ch0512-prepare-result1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0512-prepare-result1.png -------------------------------------------------------------------------------- /img/ch05/ch0513-prepare-result2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0513-prepare-result2.png -------------------------------------------------------------------------------- /img/ch05/ch0514-question5.4v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/ch05/ch0514-question5.4v2.png -------------------------------------------------------------------------------- /img/datawhale_code.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/datawhale_code.jpeg -------------------------------------------------------------------------------- /img/feishu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/img/feishu.jpg -------------------------------------------------------------------------------- /materials/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /materials/SQL基础教程-V2.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/wonderful-sql/99881fd07aed013043159bd97f905454e1cf595b/materials/SQL基础教程-V2.0.pdf -------------------------------------------------------------------------------- /materials/create_table_sql/shop.sql: -------------------------------------------------------------------------------- 1 | /* 2022.02.05 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'); 211 | 212 | CREATE view `view_product` as 213 | SELECT * FROM product; 214 | 215 | 216 | -- ---------------------------- 217 | -- Table structure for sales_statistics_1 218 | -- ---------------------------- 219 | DROP TABLE IF EXISTS `sales_statistics_1`; 220 | CREATE TABLE `sales_statistics_1` ( 221 | `sdate` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '销售日期', 222 | `product_id` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '商品编号', 223 | `product_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '商品名称', 224 | `sales_quantity` int NULL DEFAULT NULL COMMENT '销售数量', 225 | `sales_amount` decimal(20, 2) NULL DEFAULT NULL COMMENT '销售金额' 226 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; 227 | 228 | -- ---------------------------- 229 | -- Table structure for sales_statistics_2 230 | -- ---------------------------- 231 | DROP TABLE IF EXISTS `sales_statistics_2`; 232 | CREATE TABLE `sales_statistics_2` ( 233 | `sdate` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '销售日期', 234 | `product_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '商品类型', 235 | `sales_quantity` int NULL DEFAULT NULL COMMENT '销售数量', 236 | `sales_amount` decimal(20, 2) NULL DEFAULT NULL COMMENT '销售金额' 237 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; -------------------------------------------------------------------------------- /materials/create_table_sql/决胜秋招-建表语句.sql: -------------------------------------------------------------------------------- 1 | /* v 2022.02.06 2 | * Datawhale组队学习 SQL 编程语言 task06 建表语句汇总 3 | * 4 | * 5 | */ 6 | 7 | -- task06: 8 | -- Section A 9 | 10 | -- 练习一:各部门工资最高的员工 11 | DROP TABLE if EXISTS Employee; 12 | CREATE TABLE Employee 13 | (id INT, 14 | name VARCHAR(20), 15 | salary INT, 16 | departmentid INT, 17 | PRIMARY KEY (id)); 18 | 19 | INSERT INTO Employee VALUES(1,'Joe',70000,1); 20 | INSERT INTO Employee VALUES(2,'Henry',80000,2); 21 | INSERT INTO Employee VALUES(3,'Sam',60000,2); 22 | INSERT INTO Employee VALUES(4,'Max',90000,1); 23 | 24 | 25 | DROP TABLE if EXISTS Department; 26 | CREATE TABLE Department 27 | (id INT, 28 | name VARCHAR(20), 29 | PRIMARY KEY (id)); 30 | 31 | INSERT INTO Department VALUES(1,'IT'); 32 | INSERT INTO Department VALUES(2,'Sales'); 33 | 34 | 35 | -- 练习二:换座位 36 | DROP TABLE if exists seat; 37 | CREATE TABLE seat 38 | (id INT, 39 | student VARCHAR(20), 40 | PRIMARY KEY (id)); 41 | 42 | INSERT INTO seat VALUES(1,'Abbot'); 43 | INSERT INTO seat VALUES(2,'Doris'); 44 | INSERT INTO seat VALUES(3,'Emerson'); 45 | INSERT INTO seat VALUES(4,'Green'); 46 | INSERT INTO seat VALUES(5,'Jeames'); 47 | 48 | 49 | -- 练习三:分数排名 50 | DROP TABLE if exists score; 51 | CREATE TABLE score 52 | (class INT, 53 | score_avg INT, 54 | PRIMARY KEY (class)); 55 | 56 | INSERT INTO score VALUES(1, 93); 57 | INSERT INTO score VALUES(2, 93); 58 | INSERT INTO score VALUES(3, 93); 59 | INSERT INTO score VALUES(4, 91); 60 | 61 | 62 | -- 练习四:连续出现的数字 63 | DROP TABLE if exists logs; 64 | CREATE TABLE logs 65 | (id INT, 66 | num INT, 67 | PRIMARY KEY (id)); 68 | 69 | INSERT INTO logs VALUES (1, 1); 70 | INSERT INTO logs VALUES (2, 1); 71 | INSERT INTO logs VALUES (3, 1); 72 | INSERT INTO logs VALUES (4, 2); 73 | INSERT INTO logs VALUES (5, 1); 74 | INSERT INTO logs VALUES (6, 2); 75 | INSERT INTO logs VALUES (7, 2); 76 | 77 | 78 | -- 练习五:树节点 79 | DROP TABLE if exists tree; 80 | CREATE TABLE tree 81 | (id INT, 82 | p_id INT, 83 | PRIMARY KEY (id)); 84 | 85 | INSERT INTO tree VALUES (1, null); 86 | INSERT INTO tree VALUES (2, 1); 87 | INSERT INTO tree VALUES (3, 1); 88 | INSERT INTO tree VALUES (4, 2); 89 | INSERT INTO tree VALUES (5, 2); 90 | 91 | 92 | -- 练习六:至少有五名直接下属的经理 93 | DROP TABLE if exists Employee2; 94 | CREATE TABLE Employee2 95 | (id INT, 96 | name varchar(20), 97 | department varchar(20), 98 | managerid INT, 99 | PRIMARY KEY (id)); 100 | 101 | INSERT INTO Employee2 VALUES (101, 'John', 'A', null); 102 | INSERT INTO Employee2 VALUES (102, 'Dan', 'A', 101); 103 | INSERT INTO Employee2 VALUES (103, 'James', 'A', 101); 104 | INSERT INTO Employee2 VALUES (104, 'Amy', 'A', 101); 105 | INSERT INTO Employee2 VALUES (105, 'Anne', 'A', 101); 106 | INSERT INTO Employee2 VALUES (106, 'Ron', 'B', 101); 107 | 108 | 109 | -- 练习七:查询回答率最高的问题 110 | DROP TABLE IF EXISTS survey_log; 111 | CREATE TABLE survey_log ( 112 | uid INT, 113 | action VARCHAR (20), 114 | question_id INT, 115 | answer_id INT, 116 | q_num INT, 117 | TIMESTAMP INT 118 | ); 119 | 120 | INSERT INTO survey_log VALUES (5, 'show', 285, NULL, 1, 123); 121 | INSERT INTO survey_log VALUES (5, 'answer', 285, 124124, 1, 124); 122 | INSERT INTO survey_log VALUES (5, 'show', 369, NULL, 2, 125); 123 | INSERT INTO survey_log VALUES (5, 'skip', 369, NULL, 2, 126); 124 | 125 | 126 | -- 练习八:各部门前3高工资的员工 127 | DROP TABLE IF EXISTS employee9; 128 | CREATE TABLE employee9 SELECT id, name, salary,departmentid FROM employee; 129 | 130 | 131 | INSERT INTO employee9 VALUES(5, 'Janet', 69000, 1); 132 | INSERT INTO employee9 VALUES(6, 'Randy', 85000, 1); 133 | 134 | 135 | -- 练习九:平面上最近距离 136 | DROP TABLE IF EXISTS point_2d; 137 | CREATE TABLE point_2d ( 138 | x INT, 139 | y INT 140 | ); 141 | 142 | INSERT INTO point_2d VALUES(-1, -1); 143 | INSERT INTO point_2d VALUES( 0, 0); 144 | INSERT INTO point_2d VALUES(-1, -2); 145 | 146 | 147 | -- 练习十:行程和用户 148 | DROP TABLE if EXISTS Trips; 149 | CREATE TABLE Trips 150 | (Id INT, 151 | Client_Id INT, 152 | Driver_Id INT, 153 | City_Id INT, 154 | Status VARCHAR(30), 155 | Request_at DATE, 156 | PRIMARY KEY (Id)); 157 | 158 | INSERT INTO Trips VALUES (1, 1, 10, 1, 'completed', '2013-10-1'); 159 | INSERT INTO Trips VALUES (2, 2, 11, 1, 'cancelled_by_driver', '2013-10-1'); 160 | INSERT INTO Trips VALUES (3, 3, 12, 6, 'completed', '2013-10-1'); 161 | INSERT INTO Trips VALUES (4, 4, 13, 6, 'cancelled_by_client', '2013-10-1'); 162 | INSERT INTO Trips VALUES (5, 1, 10, 1, 'completed', '2013-10-2'); 163 | INSERT INTO Trips VALUES (6, 2, 11, 6, 'completed', '2013-10-2'); 164 | INSERT INTO Trips VALUES (7, 3, 12, 6, 'completed', '2013-10-2'); 165 | INSERT INTO Trips VALUES (8, 2, 12, 12, 'completed', '2013-10-3'); 166 | INSERT INTO Trips VALUES (9, 3, 10, 12, 'completed', '2013-10-3'); 167 | INSERT INTO Trips VALUES (10, 4, 13, 12, 'cancelled_by_driver', '2013-10-3'); 168 | 169 | 170 | DROP TABLE if EXISTS Users ; 171 | CREATE TABLE Users 172 | (Users_Id INT, 173 | Banned VARCHAR(30), 174 | Role VARCHAR(30), 175 | PRIMARY KEY (Users_Id)); 176 | 177 | INSERT INTO Users VALUES (1, 'No', 'client'); 178 | INSERT INTO Users VALUES (2, 'Yes', 'client'); 179 | INSERT INTO Users VALUES (3, 'No', 'client'); 180 | INSERT INTO Users VALUES (4, 'No', 'client'); 181 | INSERT INTO Users VALUES (10, 'No', 'driver'); 182 | INSERT INTO Users VALUES (11, 'No', 'driver'); 183 | INSERT INTO Users VALUES (12, 'No', 'driver'); 184 | INSERT INTO Users VALUES (13, 'No', 'driver'); 185 | 186 | 187 | -- Section B 188 | 189 | -- 练习一:行转列 190 | DROP TABLE IF EXISTS `score2`; 191 | CREATE TABLE `score2` ( 192 | `name` varchar(20) DEFAULT NULL, 193 | `subject` varchar(20) DEFAULT NULL, 194 | `score` int DEFAULT NULL 195 | ); 196 | 197 | INSERT INTO score2 VALUES('A', 'chinese', 99); 198 | INSERT INTO score2 VALUES('A', 'math', 98); 199 | INSERT INTO score2 VALUES('A', 'english', 97); 200 | INSERT INTO score2 VALUES('B', 'chinese', 92); 201 | INSERT INTO score2 VALUES('B', 'math', 91); 202 | INSERT INTO score2 VALUES('B', 'english', 90); 203 | INSERT INTO score2 VALUES('C', 'chinese', 88); 204 | INSERT INTO score2 VALUES('C', 'math', 87); 205 | INSERT INTO score2 VALUES('C', 'english', 86); 206 | 207 | 208 | -- 练习二:列转行 209 | DROP TABLE IF EXISTS `score22`; 210 | CREATE TABLE `score22` ( 211 | `name` varchar(20) DEFAULT NULL, 212 | `chinese` int DEFAULT NULL, 213 | `math` int DEFAULT NULL, 214 | `english` int DEFAULT NULL 215 | ); 216 | 217 | INSERT INTO score22 VALUES('A', 99, 98, 97); 218 | INSERT INTO score22 VALUES('B', 92, 91, 90); 219 | INSERT INTO score22 VALUES('C', 88, 87, 86); 220 | 221 | -- 练习三:谁是明星带货主播? 222 | DROP TABLE if EXISTS anchor_sales; 223 | CREATE TABLE anchor_sales 224 | (anchor_name VARCHAR(20), 225 | date INT, 226 | sales INT); 227 | 228 | INSERT INTO anchor_sales VALUES('A', 20210101, 40000); 229 | INSERT INTO anchor_sales VALUES('B', 20210101, 80000); 230 | INSERT INTO anchor_sales VALUES('A', 20210102, 10000); 231 | INSERT INTO anchor_sales VALUES('C', 20210102, 90000); 232 | INSERT INTO anchor_sales VALUES('A', 20210103, 7500); 233 | INSERT INTO anchor_sales VALUES('C', 20210103, 80000); 234 | 235 | 236 | -- Section C 237 | 238 | -- 练习一:行转列 239 | DROP TABLE IF EXISTS row_col; 240 | create table row_col 241 | (cdate date, 242 | result varchar(255)); 243 | 244 | 245 | insert into row_col values ('2021-01-01','胜'); 246 | insert into row_col values ('2021-01-01','负'); 247 | insert into row_col values ('2021-01-03','胜'); 248 | insert into row_col values ('2021-01-03','负'); 249 | insert into row_col values ('2021-01-01','胜'); 250 | insert into row_col values ('2021-01-03','负'); 251 | 252 | 253 | -- 练习二:列转行 254 | DROP TABLE IF EXISTS col_row; 255 | create table col_row 256 | (`比赛日期` date 257 | ,`胜` int 258 | ,`负` int); 259 | 260 | insert into col_row values ('2021-01-01', 4, 1); 261 | insert into col_row values ('2021-01-03', 1, 4); 262 | 263 | -- 练习三:连续登录 264 | DROP TABLE if EXISTS t_act_records; 265 | CREATE TABLE t_act_records 266 | (uid VARCHAR(20), 267 | imp_date DATE); 268 | 269 | INSERT INTO t_act_records VALUES('u1001', 20210101); 270 | INSERT INTO t_act_records VALUES('u1002', 20210101); 271 | INSERT INTO t_act_records VALUES('u1003', 20210101); 272 | INSERT INTO t_act_records VALUES('u1003', 20210102); 273 | INSERT INTO t_act_records VALUES('u1004', 20210101); 274 | INSERT INTO t_act_records VALUES('u1004', 20210102); 275 | INSERT INTO t_act_records VALUES('u1004', 20210103); 276 | INSERT INTO t_act_records VALUES('u1004', 20210104); 277 | INSERT INTO t_act_records VALUES('u1004', 20210105); 278 | 279 | -- 练习四:用户购买商品推荐 280 | -- ---------------------------- 281 | -- Table structure for orders 282 | -- ---------------------------- 283 | DROP TABLE IF EXISTS `orders`; 284 | CREATE TABLE `orders` ( 285 | `user_id` int NOT NULL, 286 | `product_id` int NOT NULL 287 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; 288 | 289 | -- ---------------------------- 290 | -- Records of orders 291 | -- ---------------------------- 292 | INSERT INTO `orders` VALUES (123, 1); 293 | INSERT INTO `orders` VALUES (123, 2); 294 | INSERT INTO `orders` VALUES (123, 3); 295 | INSERT INTO `orders` VALUES (456, 1); 296 | INSERT INTO `orders` VALUES (456, 2); 297 | INSERT INTO `orders` VALUES (456, 4); 298 | 299 | -- 练习六:LEFT JOIN 是否可能会出现多出的行?为什么? 300 | -- ---------------------------- 301 | -- Table structure for t1 302 | -- ---------------------------- 303 | DROP TABLE IF EXISTS `t1`; 304 | CREATE TABLE `t1` ( 305 | `id` int NOT NULL, 306 | `name` varchar(255) NULL DEFAULT NULL, 307 | `score` int NULL DEFAULT NULL, 308 | PRIMARY KEY (`id`) USING BTREE 309 | ) ENGINE = InnoDB ROW_FORMAT = Dynamic; 310 | 311 | -- ---------------------------- 312 | -- Records of t1 313 | -- ---------------------------- 314 | INSERT INTO `t1` VALUES (1, 'aaa', 90); 315 | INSERT INTO `t1` VALUES (2, 'bbb', 80); 316 | INSERT INTO `t1` VALUES (3, 'ccc', 70); 317 | INSERT INTO `t1` VALUES (4, 'ddd', 60); 318 | INSERT INTO `t1` VALUES (5, '' , 90); 319 | INSERT INTO `t1` VALUES (6, '' , 100); 320 | 321 | -- ---------------------------- 322 | -- Table structure for t2 323 | -- ---------------------------- 324 | DROP TABLE IF EXISTS `t2`; 325 | CREATE TABLE `t2` ( 326 | `id` int NOT NULL, 327 | `name` varchar(255) NULL DEFAULT NULL, 328 | `city` varchar(255) NULL DEFAULT NULL, 329 | PRIMARY KEY (`id`) USING BTREE 330 | ) ENGINE = InnoDB ROW_FORMAT = Dynamic; 331 | 332 | -- ---------------------------- 333 | -- Records of t2 334 | -- ---------------------------- 335 | INSERT INTO `t2` VALUES (1, 'aaa', 'beijing'); 336 | INSERT INTO `t2` VALUES (2, 'bbb', 'tianjin'); 337 | INSERT INTO `t2` VALUES (3, 'ccc', 'chengdu'); 338 | INSERT INTO `t2` VALUES (4, '' , 'shenzhen'); 339 | INSERT INTO `t2` VALUES (5, '' , 'qingdao'); 340 | INSERT INTO `t2` VALUES (6, '' , 'guangzhou'); 341 | 342 | -------------------------------------------------------------------------------- /materials/free_navicat_download/baidu_cloud_url.md: -------------------------------------------------------------------------------- 1 | 2 | 链接:[https://pan.baidu.com/s/1xdAEXkATNfIS_yhYNROlAQ](https://pan.baidu.com/s/1xdAEXkATNfIS_yhYNROlAQ) 3 | 4 | 提取码:vktl 5 | -------------------------------------------------------------------------------- /materials/readme.md: -------------------------------------------------------------------------------- 1 | 课程所用建表语句、navicat免费版客户端、pdf版本课程内容(有延迟) 2 | -------------------------------------------------------------------------------- /materials/参考答案.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | 参考答案仅供参考,并不是唯一的答案,如果有疑问、建议或者勘误,请提交 `issue` 或者 `Pull request` 给我们,我们将会及时响应。 4 | 5 | 非组队期间:可以任意查看参考答案。 6 | 7 | 组队期间:每个任务打卡完成之后,才可以查看答案。 8 | 9 | 【task01参考答案】 10 | [https://xz9235vqyp.feishu.cn/docs/doccnjASyISYXEDhI4W95Rycorh](https://xz9235vqyp.feishu.cn/docs/doccnMduaNhilUIrlldFqmNWIzf) 11 | 12 | 【task02参考答案】 13 | https://xz9235vqyp.feishu.cn/docs/doccnjASyISYXEDhI4W95Rycorh 14 | 15 | 【task03参考答案】 16 | https://xz9235vqyp.feishu.cn/docs/doccn4Ll8TU5b76SQ93uHlaHjEd 17 | 18 | 【task04参考答案】 19 | https://xz9235vqyp.feishu.cn/docs/doccnnBUWyb5NQZ27fVuTR2Tvie 20 | 21 | 【task05参考答案】 22 | https://xz9235vqyp.feishu.cn/docs/doccn8YjyxIyV2aQ1J7mQdMHNrd 23 | 24 | 【task06参考答案】 25 | https://xz9235vqyp.feishu.cn/docs/doccnruf8gPtnAm9gbxKJRU0pZf#kOh8xj 26 | -------------------------------------------------------------------------------- /materials/附录1:SQL语法规范.md: -------------------------------------------------------------------------------- 1 | # 一、语法规范 2 | 3 | ```sql 4 | -- 样例一 5 | (SELECT flora.species_name 6 | ,AVG(flora.height) AS average_height 7 | ,AVG(flora.diameter) AS average_diameter 8 | FROM flora 9 | WHERE flora.species_name = 'Banksia' 10 | OR flora.species_name = 'Sheoak' 11 | OR flora.species_name = 'Wattle' 12 | GROUP BY flora.species_name, flora.observation_date) 13 | UNION ALL 14 | (SELECT botanic.species_name 15 | ,AVG(b.height) AS average_height 16 | ,AVG(b.diameter) AS average_diameter 17 | FROM botanic_garden_flora AS botanic 18 | WHERE botanic.species_name = 'Banksia' 19 | OR botanic.species_name = 'Sheoak' 20 | OR botanic.species_name = 'Wattle' 21 | GROUP BY botanic.species_name, botanic.observation_date); 22 | -- 样例二 23 | SELECT botanic.species_name 24 | ,AVG(b.height) AS average_height 25 | ,AVG(b.diameter) AS average_diameter 26 | FROM botanic_garden_flora AS botanic 27 | WHERE botanic.species_name IN (SELECT species_name 28 | FROM flora 29 | WHERE height >= 3) 30 | GROUP BY botanic.species_name, botanic.observation_da; 31 | 32 | -- 样例三 33 | SELECT SP.shop_id, SP.shop_name, SP.product_id, P.product_name, P.product_type, P.purchase_price 34 | FROM shopproduct AS SP 35 | INNER JOIN -- product 36 | (SELECT product_name, product_type, purchase_price 37 | FROM Product ) AS P 38 | ON SP.product_id=P.product_id 39 | WHERE P.product_type='衣服'; 40 | ``` 41 | 42 | **SQL语法规范总得的原则是,清楚、易读并且层次清晰。**实际场景中常常动辄几百上千行的SQL语句,如果不写清楚,事后review或者别人接手的时候,会让人怀疑人生。 43 | 44 | 当然这些规范都是笔者根据实际经验总结归纳的,并不是金科铁律,但是强烈建议新手按以下规范入门编写SQL语句。 45 | 46 | **常见注意事项如下:** 47 | 48 | 1. MySQL本身不区分大小写,但强烈要求关键字大写,表名、列名用小写; 49 | 2. 创建表时,使用统一的、描述性强的字段命名规则保证字段名是独一无二且不是保留字的,不要使用连续的下划线,不用下划线结尾;最好以字母开头 50 | 3. 关键字右对齐,且不同层级的用空格或缩进控制,使其区分开,见样例二; 51 | 4. 列名少的时候写在一行里无伤大雅;多的时候以及涉及到CASE WHEN 或者聚合计算的时候,建议分行写;个人习惯是逗号在列名前面,方便之后删除某些列,放列名后亦可; 52 | 5. 表别名和列别名尽量用有具体含义的词组,不要用a b c,不然以后review的时候会非常痛苦; 53 | 6. 运算符前后都加一个空格; 54 | 7. 当用到多个表时,请在所有列名前写上引用的表别名,不要嫌麻烦; 55 | 8. 每条命令用分号结尾; 56 | 9. 养成随手写注释的习惯,注释方法: 57 | ```plain 58 | 单行注释 #注释文字 59 | 单行注释 -- 注释文字 60 | 多行注释:/* 注释文字 */ 61 | ``` 62 | 63 | P.S. 养成良好的书写习惯,可以避免以后发生流血事件 →_→ 64 | 65 | # 参考资料: 66 | 67 | 1. SQL编程风格[https://zhuanlan.zhihu.com/p/27466166](https://zhuanlan.zhihu.com/p/27466166?fileGuid=NJkbE0rrXRi1zrqR) 68 | 2. SQL Style Guide[https://www.sqlstyle.guide/](https://www.sqlstyle.guide/?fileGuid=NJkbE0rrXRi1zrqR) 69 | 70 | -------------------------------------------------------------------------------- /materials/附录2: [选学] 使用 Python 连接 MySQL.md: -------------------------------------------------------------------------------- 1 | # 4.使用 Python 连接 MySQL 2 | 3 | Python是最近几年最热门的编程语言,特别是在数据科学和机器学习领域,Python已经成为了主流的编程语言.和其他如JAVA,C++等通用编程语言一样, Python也能够连接MySQL执行查询,并将结果从数据库中取回,以供Python程序使用。 4 | 5 | 以下我们假设大家已经安装了anaconda套装(推荐,如尚未安装anaconda可参考[https://zhuanlan.zhihu.com/p/75717350](https://zhuanlan.zhihu.com/p/75717350?fileGuid=CzxMOL7JZicLAS3Q))或者自行安装配置好了Python环境加Jupyternotebook,接下来介绍在Jupyter notebook 中使用Python3的PyMySQL模块连接MySQL并执行SQL查询和取回查询结果的方法。 6 | 7 | #### 4.1 安装 PyMySQL 模块 8 | 9 | 首先安装PyMySQL模块,这里选择直接在jupyternotebook中进行安装. 10 | 11 | ```python 12 | # 安装 pymsql 模块 13 | !pip install pymysql 14 | ``` 15 | 安装完成后, 会有如下的输出,表示已成功安装该模块. 16 | ![图片](https://uploader.shimo.im/f/fDmDoys19eYZi4Ja.png!thumbnail?fileGuid=CzxMOL7JZicLAS3Q) 17 | 18 | #### 4.2 导入模块 19 | 20 | 现在我们就可以导入 PyMySQL 模块,然后建立到 MySQL的连接了.如果下述代码执行后没有任何输出,则是正常导入了该模块。 21 | 22 | ```python 23 | # 导入 pymysql 模块 24 | import pymysql 25 | ``` 26 | #### 4.3 使用PyMySQL的connect函数建立到MySQL的连接 27 | 28 | 导入PyMySQL 模块后, 我们使用该模块中的connect函数建立到本机MySQL服务的连接: 29 | 30 | ```python 31 | # 连接MySQL.密码请使用你自己设置的密码,shop为上一节导入的示例数据库 32 | conn = pymysql.connect(host="127.0.0.1", user="root",password="123456",database="shop",charset="utf8") 33 | ``` 34 | >注: 35 | >pymysql.connect()有很多的参数,但是上述最基本的参数就能保证连接正常,并且能使得中文字符正确显示. 36 | >关于该函数更多的参数介绍 37 | ```python 38 | host=None,# 要连接的主机地址, 本机上的 MySQL 使用 127.0.0.1 39 | user=None,# 用于登录的数据库用户名, 例如 root. 40 | password='',# 上述账号的相应密码 41 | database=None,# 要连接的数据库,本教程使用的是来源于的 shop 数据库 42 | port=0,# 端口,一般为 3306 43 | unix_socket=None,# 选择是否要用 unix_socket 而不是 TCP/IP 44 | charset='',# 字符编码, 需要支持中文请使用"utf8" 45 | sql_mode=None,# Default SQL_MODE to use. 46 | read_default_file=None,# 从默认配置文件(my.ini 或 my.cnf)中读取参数 47 | conv=None,# 转换字典 48 | use_unicode=None,# 是否使用 unicode 编码 49 | client_flag=0,# Custom flags to send to MySQL. Find potential values in constants.CLIENT. 50 | cursorclass=,# 选择 Cursor 类型 51 | init_command=None,# 连接建立时运行的初始语句 52 | connect_timeout=10,# 连接超时时间,(default: 10, min: 1, max: 31536000) 53 | ssl=None,# A dict of arguments similar to mysql_ssl_set()'s parameters.For now the capath and cipher arguments are not supported. 54 | read_default_group=None,# Group to read from in the configuration file. 55 | compress=None,# 不支持 56 | named_pipe=None,# 不支持 57 | no_delay=None,# 58 | autocommit=False,# 是否自动提交事务 59 | db=None,# 同 database,为了兼容 MySQLdb 60 | passwd=None,# 同 password,为了兼容 MySQLdb 61 | local_infile=False,# 是否允许载入本地文件 62 | max_allowed_packet=16777216,# 限制 `LOCAL DATA INFILE` 大小 63 | defer_connect=False,# Don't explicitly connect on contruction - wait for connect call. 64 | auth_plugin_map={},# 65 | read_timeout=None,# 66 | write_timeout=None, 67 | bind_address=None# 当客户有多个网络接口,指定一个连接到主机 68 | ``` 69 | #### 4.4 创建用于执行SQL语句的游标对象 70 | 71 | 对上述建立的连接,使用cursor 方法得到一个游标对象: 72 | 73 | ``` 74 | # 得到一个可以执行 SQL 语句的游标对象 75 | cur = conn.cursor() 76 | ``` 77 | 本教程主要是讲解SQL查询语句, 因此这里以一个读取 MySQL 数据库的表中数据的SQL查询为例. 首先定义一个 SQL 查询语句, 以取回 product 表所有数据为例: 78 | 79 | ```python 80 | # 定义要执行的 SQL 语句 81 | sql = """ 82 | SELECT * 83 | FROM product; 84 | """ 85 | ``` 86 | #### 4.5 执行SQL语句 87 | 88 | 然后使用游标对象的excute方法在MySQL数据库里执行上述SQL查询: 89 | 90 | ```python 91 | # 执行 SQL 语句 92 | cur.execute(sql) 93 | ``` 94 | #### 4.6 取回SQL语句的执行结果 95 | 96 | 完成SQL语句后, 由于我们上述定义的SQL语句是一个SQL查询, 因此可以接着使用游标对象的 fetchall 方法取回查询结果: 97 | 98 | ```python 99 | # 取回查询结果 100 | # 如果需要将取回的结果赋值给一个变量, 可以使用 data = cur.fetchall() 101 | cur.fetchall() 102 | ``` 103 | 取回的结果是一个嵌套的元组, 且没有数据表中的列名. 上述代码正确执行后得到如下结果: 104 | ![图片](https://uploader.shimo.im/f/vw4N03QEZtmath8t.png!thumbnail?fileGuid=CzxMOL7JZicLAS3Q) 105 | 106 | #### 4.7 使用pandas的read_sql函数执行SQL查询并取回结果为DataFrame 107 | 108 | 如果我们想要同时取回列名, 并且想让取回的数据具有更好的结构化, 则可以使用 pandas 库的 read_sql 函数来读取检索结果: 109 | 110 | ```python 111 | # 另一种执行SQL查询并取回检索结果的方法是使用 pandas 库读取检索结果 112 | # 如未安装pandas可在notebook里使用"!pip install pandas"进行安装 113 | import pandas as pd 114 | pd.read_sql(sql,conn) 115 | # 如果需要将取回的结果赋值给一个变量, 可以使用 df = pd.read_sql(sql,conn) 116 | ``` 117 | 此时取回的结果就是一个 pandas 中的 DataFrame 对象了, 它在jupyter notebook中看起来就是一张表格。 118 | ![图片](https://uploader.shimo.im/f/pCcAkhG9B75q49R8.png!thumbnail?fileGuid=CzxMOL7JZicLAS3Q) 119 | 120 | >注: 121 | >在使用pandas的read_sql函数时, 只需要建立Python到MySQL的连接就可以了, 不需要建立游标. 122 | >关于该函数的更多参数介绍: 123 | ```python 124 | # read_sql函数各参数的意义: 125 | sql # 必备参数, SQL命令字符串 126 | con # 连接sql数据库的engine,我们这里使用pymysql的connect函数建立 127 | index_col=None # 选择某一列作为pandas对象的index 128 | coerce_float=True # 将数字形式的字符串直接以float型读入 129 | parse_dates=None # 将数据表中datetime类型的列读取为datetime型数据,与pd.to_datetime 功能类似. 可直接提供需要转换的列名然后以默认的日期形式转换, 也可以用字典的格式提供列名和转换的日期格式,比如{列名A: 时间日期格式1, 列名B: 时间日期格式2}, 其中的时间日期格式需要是合法的格式, 例如:"%Y:%m:%H:%M:%S". 130 | columns # 要读取的列,基本不会用到, 因为我们在sql命令里面就可以指定需要取回的列. 131 | chunksize # 对于取回大批量数据时有用. 如果提供了一个整数值,那么就会返回一个generator,每次输出的行数就等于你指定的该参数的值. 132 | ``` 133 | #### 4.8 关闭游标和数据库连接 134 | 135 | 最后, 在完成数据检索和取回数据后, 需要手动关闭数据库连接。 136 | 137 | 首先关闭游标对象: 138 | 139 | ```python 140 | # 关闭游标对象 141 | cur.close() 142 | ``` 143 | 然后关闭数据库连接 144 | ```python 145 | # 关闭数据库连接 146 | conn.close() 147 | ``` 148 | #### 4.9 使用函数封装数据库连接 149 | 150 | 上述流程就是使用PyMySQL连接到本机的MySQL数据库的完整过程了。 151 | 152 | 为了便于复用上述代码, 我们可以把上述流程封装为一个函数, 函数的参数为SQL查询语句: 153 | 154 | ```python 155 | # 封装为函数 156 | def conn2mysql(sql): 157 |     """ 158 |     函数的参数为一个字符串类型的 SQL 语句 159 |     返回值为一个 DataFrame 对象 160 |     """ 161 |     from pandas import read_sql 162 |     from pymysql import connect 163 |     # 连接本机上的MySQL服务器中的shop数据库 164 |     conn = connect(host="127.0.0.1", user="root",password="123456",database="shop",charset="utf8") 165 | # 使用 pandas 的 read_sql 函数执行 SQL 语句并取回检索结果 166 |     df=read_sql(sql,conn) 167 |     # 关闭数据库连接 168 |     conn.close() 169 |     return df 170 | ``` 171 | 使用上述函数执行 sql 172 | ```python 173 | # 定义要执行的 SQL 查询 174 | sql = """ 175 | SELECT * 176 | FROM product; 177 | """ 178 | # 执行 sql 查询并取回查询结果 179 | df = conn2mysql(sql) 180 | # 查看取回的结果 181 | df 182 | ``` 183 | ![图片](https://uploader.shimo.im/f/FGvJLOWVp46GWF9T.png!thumbnail?fileGuid=CzxMOL7JZicLAS3Q) 184 | 185 | 将数据库中的查询取回为pandas对象后, 就可以在Python中使用各种工具进行进一步的处理了。 186 | 187 | -------------------------------------------------------------------------------- /practice-questions/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /practice-questions/question_list.md: -------------------------------------------------------------------------------- 1 | # 题目 Q001 2 | ## 背景描述 3 | 复兴集团公司中有一份组织架构信息,包括部门信息及部分具有领导职务的雇员信息,详见下图示例: 4 | 5 | | role_id | role_name | parent_id | level | role_type | 6 | |:----------|-----------|:-----------|-------|------------| 7 | | 01 | 复兴集团公司 | | L1 | department | 8 | | 0101 | 总部 | 01 | L2 | department | 9 | | 010101 | 总裁办公室 | 0101 | L3 | department | 10 | | 0102 | 北京分公司 | 01 | L2 | department | 11 | | 010201 | 项目部 | 0102 | L3 | department | 12 | | 01020101 | 项目一部 | 010201 | L4 | department | 13 | | 01020102 | 项目部总监 | 010201 | L4 | employee | 14 | | 010202 | 市场部 | 0102 | L3 | department | 15 | | 01020201 | 市场部总监 | 010202 | L4 | employee | 16 | | 01020202 | 市场部专员 | 010202 | L4 | employee | 17 | 18 | ## 需求描述 19 | 现在想提取一份仅包含部门信息的组织架构信息,要求从左向右依次展示各层级部门信息,去除所有雇员信息,需求示例如下图所示: 20 | | dep_id_l1 | dep_name_l1 | dep_id_l2 | dep_name_l2 | dep_id_l3 | dep_name_l3 | dep_id_l4 | dep_name_l4 | 21 | |-----------|-------------|-----------|-------------|-----------|-------------|-----------|-------------| 22 | | 01 | 复兴集团公司 | 0101 | 总部 | 010101 | 总裁办公室 | | | 23 | | 01 | 复兴集团公司 | 0102 | 北京分公司 | 010201 | 项目部 | 01020101 | 项目一部 | 24 | | 01 | 复兴集团公司 | 0102 | 北京分公司 | 010202 | 市场部 | 25 | ## 考察点 26 | 27 | 自联结 28 | 29 | ## 建表语句 30 | 31 | ```sql 32 | -- ---------------------------- 33 | -- Table structure for dep_list 34 | -- ---------------------------- 35 | DROP TABLE IF EXISTS `dep_list`; 36 | CREATE TABLE `dep_list` ( 37 | `role_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色编号', 38 | `role_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色名称', 39 | `parent_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '父编号', 40 | `level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '层级', 41 | `role_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色类型', 42 | PRIMARY KEY (`role_id`) USING BTREE 43 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; 44 | ``` 45 | 46 | ## 示例数据信息 47 | 48 | ```sql 49 | -- ---------------------------- 50 | -- Records of dep_list 51 | -- ---------------------------- 52 | INSERT INTO `dep_list` VALUES ('01', '复兴集团公司', '', 'L1', 'department'); 53 | INSERT INTO `dep_list` VALUES ('0101', '总部', '01', 'L2', 'department'); 54 | INSERT INTO `dep_list` VALUES ('010101', '总裁办公室', '0101', 'L3', 'department'); 55 | INSERT INTO `dep_list` VALUES ('0102', '北京分公司', '01', 'L2', 'department'); 56 | INSERT INTO `dep_list` VALUES ('010201', '项目部', '0102', 'L3', 'department'); 57 | INSERT INTO `dep_list` VALUES ('01020101', '项目一部', '010201', 'L4', 'department'); 58 | INSERT INTO `dep_list` VALUES ('01020102', '项目部总监', '010201', 'L4', 'employee'); 59 | INSERT INTO `dep_list` VALUES ('010202', '市场部', '0102', 'L3', 'department'); 60 | INSERT INTO `dep_list` VALUES ('01020201', '市场部总监', '010202', 'L4', 'employee'); 61 | INSERT INTO `dep_list` VALUES ('01020202', '市场部专员', '010202', 'L4', 'employee'); 62 | ``` 63 | --------------------------------------------------------------------------------