CodeRoadMap
路线图学习路径文章题库资源社区

浏览

首页路线图学习路径知识库题库文章资源社区我的学习
CodeRoadMap

中文编程学习导航:路线图、讲义与题库,进度可同步。

路线图学习路径文章题库社区

© 2026 CodeRoadMap

津ICP备2026012044号-1|coderoadmap@126.com
首页/Python 100 天/41.MySQL新特性

课程目录

  1. 0101.初识Python
  2. 0202.第一个Python程序
  3. 0303.Python语言中的变量
  4. 0404.Python语言中的运算符
  5. 0505.分支结构
  6. 0606.循环结构
  7. 0707.分支和循环结构实战
  8. 0808.常用数据结构之列表-1
  9. 0909.常用数据结构之列表-2
  10. 1010.常用数据结构之元组
  11. 1111.常用数据结构之字符串
  12. 1212.常用数据结构之集合
  13. 1313.常用数据结构之字典
  14. 1414.函数和模块
  15. 1515.函数应用实战
  16. 1616.函数使用进阶
  17. 1717.函数高级应用
  18. 1818.面向对象编程入门
  19. 1919.面向对象编程进阶
  20. 2020.面向对象编程应用
  21. 2121.文件读写和异常处理
  22. 2222.对象的序列化和反序列化
  23. 2323.Python读写CSV文件
  24. 2424.Python读写Excel文件-1
  25. 2525.Python读写Excel文件-2
  26. 2626.Python操作Word和PowerPoint文件
  27. 2727.Python操作PDF文件
  28. 2828.Python处理图像
  29. 2929.Python发送邮件和短信
  30. 3030.正则表达式的应用
  31. 3131.Python语言进阶
  32. 3232-33.Web前端入门
  33. 3334-35.玩转Linux操作系统
  34. 3436.关系型数据库和MySQL概述
  35. 3537.SQL详解之DDL
  36. 3638.SQL详解之DML
  37. 3739.SQL详解之DQL
  38. 3840.SQL详解之DCL
  39. 3941.MySQL新特性
  40. 4042.视图、函数和过程
  41. 4143.索引
  42. 4244.Python接入MySQL数据库
  43. 4345.Hive实战
  44. 4446.Django快速上手
  45. 4547.深入模型
  46. 4648.静态资源和Ajax请求
  47. 4749.Cookie和Session
  48. 4850.制作报表
  49. 4951.日志和调试工具栏
  50. 5052.中间件的应用
  51. 5153.前后端分离开发入门
  52. 5254.RESTful架构和DRF入门
  53. 5355.RESTful架构和DRF进阶
  54. 5456.使用缓存
  55. 5557.接入三方平台
  56. 5658.异步任务和定时任务
  57. 5759.单元测试
  58. 5860.项目上线
  59. 5961.网络数据采集概述
  60. 6062.用Python获取网络资源-1
  61. 6162.用Python解析HTML页面-2
  62. 6263.并发编程在爬虫中的应用
  63. 6363.Python中的并发编程-1
  64. 6463.Python中的并发编程-2
  65. 6563.Python中的并发编程-3
  66. 6664.使用Selenium抓取网页动态内容
  67. 6765.爬虫框架Scrapy简介
  68. 6866.数据分析概述
  69. 6967.环境准备
  70. 7068.NumPy的应用-1
  71. 7169.NumPy的应用-2
  72. 7270.NumPy的应用-3
  73. 7371.NumPy的应用-4
  74. 7472.深入浅出pandas-1
  75. 7573.深入浅出pandas-2
  76. 7674.深入浅出pandas-3
  77. 7775.深入浅出pandas-4
  78. 7876.深入浅出pandas-5
  79. 7977.深入浅出pandas-6
  80. 8078.数据可视化-1
  81. 8179.数据可视化-2
  82. 8280.数据可视化-3
  83. 8381.浅谈机器学习
  84. 8482.k最近邻算法
  85. 8583.决策树和随机森林
  86. 8684.朴素贝叶斯算法
  87. 8785.回归模型
  88. 8886.K-Means聚类算法
  89. 8987.集成学习算法
  90. 9088.神经网络模型
  91. 9189.自然语言处理入门
  92. 9290.机器学习实战
  93. 9391.团队项目开发的问题和解决方案
  94. 9492.Docker容器技术详解
  95. 9593.MySQL性能优化
  96. 9694.网络API接口设计
  97. 9795.使用Django开发商业项目
  98. 9896.软件测试和自动化测试
  99. 9997.电商网站技术要点剖析
  100. 10098.项目部署上线和性能调优
  101. 10199.面试中的公共问题
  102. 102100.补充内容
第 39 课1 天

41.MySQL新特性

很多开发者在使用关系型数据库做数据持久化的时候,常常感到结构化的存储缺乏灵活性,因为必须事先设计好所有的列以及对应的数据类型。在业务发展和变化的过程中,如果需要

课程内容

MySQL新特性

JSON类型

很多开发者在使用关系型数据库做数据持久化的时候,常常感到结构化的存储缺乏灵活性,因为必须事先设计好所有的列以及对应的数据类型。在业务发展和变化的过程中,如果需要修改表结构,这绝对是比较麻烦和难受的事情。从 MySQL 5.7 版本开始,MySQL引入了对 JSON 数据类型的支持(MySQL 8.0 解决了 JSON 的日志性能瓶颈问题),用好 JSON 类型,其实就是打破了关系型数据库和非关系型数据库之间的界限,为数据持久化操作带来了更多的便捷。

JSON 类型主要分为 JSON 对象和 JSON数组两种,如下所示。

  1. JSON 对象
{"name": "骆昊", "tel": "13122335566", "QQ": "957658"}
  1. JSON 数组
[1, 2, 3]
[{"name": "骆昊", "tel": "13122335566"}, {"name": "王大锤", "QQ": "123456"}]

哪些地方需要用到JSON类型呢?举一个简单的例子,现在很多产品的用户登录都支持多种方式,例如手机号、微信、QQ、新浪微博等,但是一般情况下我们又不会要求用户提供所有的这些信息,那么用传统的设计方式,就需要设计多个列来对应多种登录方式,可能还需要允许这些列存在空值,这显然不是很好的选择;另一方面,如果产品又增加了一种登录方式,那么就必然要修改之前的表结构,这就更让人痛苦了。但是,有了 JSON 类型,刚才的问题就迎刃而解了,我们可以做出如下所示的设计。

CREATE TABLE `tb_test`
(
`user_id`    bigint unsigned,
`login_info` json,
PRIMARY KEY (`user_id`)
);

INSERT INTO `tb_test` 
VALUES 
    (1, '{"tel": "13122335566", "QQ": "654321", "wechat": "jackfrued"}'),
    (2, '{"tel": "13599876543", "weibo": "wangdachui123"}');

如果要查询用户的手机和微信号,可以用如下所示的 SQL 语句。

SELECT `user_id`
     , JSON_UNQUOTE(JSON_EXTRACT(`login_info`, '$.tel')) AS 手机号
     , JSON_UNQUOTE(JSON_EXTRACT(`login_info`, '$.wechat')) AS 微信 
FROM `tb_test`;
+---------+-------------+-----------+
| user_id | 手机号      | 微信       |
+---------+-------------+-----------+
|       1 | 13122335566 | jackfrued |
|       2 | 13599876543 | NULL      |
+---------+-------------+-----------+

因为支持 JSON 类型,MySQL 也提供了配套的处理 JSON 数据的函数,就像上面用到的json_extract和json_unquote。当然,上面的 SQL 还有更为便捷的写法,如下所示。

SELECT `user_id`
     , `login_info` ->> '$.tel' AS 手机号
     , `login_info` ->> '$.wechat' AS 微信
  FROM `tb_test`;

再举个例子,如果我们的产品要实现用户画像功能(给用户打标签),然后基于用户画像给用户推荐平台的服务或消费品之类的东西,我们也可以使用 JSON 类型来保存用户画像数据,示意代码如下所示。

创建画像标签表。

CREATE TABLE `tb_tags`
(
`tag_id`   int unsigned NOT NULL COMMENT '标签ID',
`tag_name` varchar(20)  NOT NULL COMMENT '标签名',
PRIMARY KEY (`tag_id`)
);

INSERT INTO `tb_tags` (`tag_id`, `tag_name`) 
VALUES
    (1, '70后'),
    (2, '80后'),
    (3, '90后'),
    (4, '00后'),
    (5, '爱运动'),
    (6, '高学历'),
    (7, '小资'),
    (8, '有房'),
    (9, '有车'),
    (10, '爱看电影'),
    (11, '爱网购'),
    (12, '常点外卖');

为用户打标签。

CREATE TABLE `tb_users_tags`
(
`user_id`   bigint unsigned NOT NULL COMMENT '用户ID',
`user_tags` json            NOT NULL COMMENT '用户标签'
);

INSERT INTO `tb_users_tags`
VALUES
    (1, '[2, 6, 8, 10]'),
    (2, '[3, 10, 12]'),
    (3, '[3, 8, 9, 11]');

接下来,我们通过一组查询来了解 JSON 类型的巧妙之处。

  1. 查询爱看电影(有10这个标签)的用户ID。

    SELECT `user_id`
      FROM `tb_users_tags`
     WHERE 10 MEMBER OF (`user_tags`->'$');
    
  2. 查询爱看电影(有10这个标签)的80后(有2这个标签)用户ID。

    SELECT `user_id`
      FROM `tb_users_tags`
     WHERE JSON_CONTAINS(`user_tags`->'$', '[2, 10]');
    
  3. 查询爱看电影或80后或90后的用户ID。

    SELECT `user_id`
      FROM `tb_users_tags`
     WHERE JSON_OVERLAPS(user_tags->'$', '[2, 3, 10]');
    

说明:上面的查询用到了member of谓词和两个 JSON 函数,json_contains可以检查 JSON 数组是否包含了指定的元素,而json_overlaps可以检查 JSON 数组是否与指定的数组有重叠部分。

窗口函数

MySQL 从8.0开始支持窗口函数,大多数商业数据库和一些开源数据库早已提供了对窗口函数的支持,有的也将其称之为 OLAP(联机分析和处理)函数,听名字就知道跟统计和分析相关。为了帮助大家理解窗口函数,我们先说说窗口的概念。

窗口可以理解为记录的集合,窗口函数也就是在满足某种条件的记录集合上执行的特殊函数,对于每条记录都要在此窗口内执行函数。窗口函数和我们上面讲到的聚合函数比较容易混淆,二者的区别主要在于聚合函数是将多条记录聚合为一条记录,窗口函数是每条记录都会执行,执行后记录条数不会变。窗口函数不仅仅是几个函数,它是一套完整的语法,函数只是该语法的一部分,基本语法如下所示:

<窗口函数> OVER (PARTITION BY <用于分组的列名> ORDER BY <用于排序的列名>  ROWS BETWEEN ... AND ...)
<窗口函数> OVER (PARTITION BY <用于分组的列名> ORDER BY <用于排序的列名> RANGE BETWEEN ... AND ...)

上面语法中,窗口函数的位置可以放以下两种函数:

  1. 专用窗口函数,包括:lead、lag、first_value、last_value、rank、dense_rank和row_number等。
  2. 聚合函数,包括:sum、avg、max、min和count等。

下面为大家举几个使用窗口函数的简单例子,我们直接使用上一课创建的 hrs 数据库。

例子1:查询按月薪从高到低排在第4到第6名的员工的姓名和月薪。

SELECT * 
  FROM (SELECT `ename`
             , `sal`
             , ROW_NUMBER() over (ORDER BY `sal` DESC) AS `rk`
	      FROM `tb_emp`) AS `temp`
 WHERE `rk` between 4 and 6;

说明:上面使用的函数row_number()可以为每条记录生成一个行号,在实际工作中可以根据需要将其替换为rank()或dense_rank()函数,三者的区别可以参考官方文档或阅读《通俗易懂的学会:SQL窗口函数》进行了解。在MySQL 8以前的版本,我们可以通过下面的方式来完成类似的操作。

select `rank`, `ename`, `sal` from (
       select @a:=@a+1 as `rank`, `ename`, `sal` 
       from `tb_emp`, (select @a:=0) as t1 order by `sal` desc
) as `temp` where `rank` between 4 and 6;

例子2:查询每个部门月薪最高的两名的员工的姓名和部门名称。

select `ename`, `sal`, `dname` 
from (
    select 
        `ename`, `sal`, `dno`,
        rank() over (partition by `dno` order by `sal` desc) as `rank`
    from `tb_emp`
) as `temp` natural join `tb_dept` where `rank`<=2;

说明:在MySQL 8以前的版本,我们可以通过下面的方式来完成类似的操作。

select `ename`, `sal`, `dname` from `tb_emp` as `t1` 
natural join `tb_dept` 
where (
        select count(*) from `tb_emp` as `t2` 
        where `t1`.`dno`=`t2`.`dno` and `t2`.`sal`>`t1`.`sal` 
)<2 order by `dno` asc, `sal` desc;
← 上一课40.SQL详解之DCL下一课 →42.视图、函数和过程