第十八章、MySQL8.0的其它新特性.sql 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #第十八章、MySQL8.0的其它新特性
  2. CREATE DATABASE dbtest18;
  3. USE dbtest18;
  4. #一、窗口函数
  5. #1.1、演示窗口函数的效果
  6. CREATE TABLE sales(
  7. id INT PRIMARY KEY AUTO_INCREMENT,
  8. city VARCHAR(15),
  9. county VARCHAR(15),
  10. sales_value DECIMAL
  11. );
  12. INSERT INTO sales(city,county,sales_value)
  13. VALUES
  14. ('北京','海淀',10.00),
  15. ('北京','朝阳',20.00),
  16. ('上海','黄埔',30.00),
  17. ('上海','长宁',10.00);
  18. SELECT * FROM sales;
  19. #需求:现在计算这个网站在每个城市的销售总额、在全国的销售总额、每个区的销售额
  20. #占所在城市销售额中的比率,以及占总销售额中的比率。
  21. #方式一:
  22. CREATE TEMPORARY TABLE a -- 创建临时表
  23. SELECT SUM(sales_value) AS sales_value -- 计算总计金额
  24. FROM sales;
  25. SELECT * FROM a;
  26. CREATE TEMPORARY TABLE b -- 创建临时表
  27. SELECT city,SUM(sales_value) AS sales_value -- 计算城市销售合计
  28. FROM sales
  29. GROUP BY city;
  30. SELECT * FROM b;
  31. SELECT s.city AS 城市,s.county AS 区,s.sales_value AS 区销售额,
  32. b.sales_value AS 市销售额,s.sales_value/b.sales_value AS 市比率,
  33. a.sales_value AS 总销售额,s.sales_value/a.sales_value AS 总比率
  34. FROM sales s
  35. JOIN b ON (s.city=b.city) -- 连接市统计结果临时表
  36. JOIN a -- 连接总计金额临时表
  37. ORDER BY s.city,s.county;
  38. #方式二:
  39. SELECT city AS 城市,county AS 区,sales_value AS 区销售额,
  40. SUM(sales_value) OVER(PARTITION BY city) AS 市销售额, -- 计算市销售额
  41. sales_value/SUM(sales_value) OVER(PARTITION BY city) AS 市比率,
  42. SUM(sales_value) OVER() AS 总销售额, -- 计算总销售额
  43. sales_value/SUM(sales_value) OVER() AS 总比率
  44. FROM sales
  45. ORDER BY city,county;
  46. #2、介绍窗口函数
  47. CREATE TABLE employees
  48. AS
  49. SELECT * FROM atguigudb.employees;
  50. SELECT * FROM employees;
  51. #准备工作
  52. CREATE TABLE goods(
  53. id INT PRIMARY KEY AUTO_INCREMENT,
  54. category_id INT,
  55. category VARCHAR(15),
  56. NAME VARCHAR(30),
  57. price DECIMAL(10,2),
  58. stock INT,
  59. upper_time DATETIME
  60. );
  61. INSERT INTO goods(category_id,category,NAME,price,stock,upper_time)
  62. VALUES
  63. (1, '女装/女士精品', 'T恤', 39.90, 1000, '2020-11-10 00:00:00'),
  64. (1, '女装/女士精品', '连衣裙', 79.90, 2500, '2020-11-10 00:00:00'),
  65. (2, '户外运动', '骑行装备', 399.90, 3500, '2020-11-10 00:00:00'),
  66. (1, '女装/女士精品', '牛仔裤', 89.90, 3500, '2020-11-10 00:00:00'),
  67. (2, '户外运动', '山地自行车', 1399.90, 2500, '2020-11-10 00:00:00'),
  68. (1, '女装/女士精品', '呢绒外套', 399.90, 1200, '2020-11-10 00:00:00'),
  69. (2, '户外运动', '自行车', 399.90, 1000, '2020-11-10 00:00:00'),
  70. (2, '户外运动', '登山杖', 59.90, 1500, '2020-11-10 00:00:00'),
  71. (1, '女装/女士精品', '卫衣', 89.90, 1500, '2020-11-10 00:00:00'),
  72. (2, '户外运动', '运动外套', 799.90, 500, '2020-11-10 00:00:00'),
  73. (1, '女装/女士精品', '百褶裙', 29.90, 500, '2020-11-10 00:00:00'),
  74. (2, '户外运动', '滑板', 499.90, 1200, '2020-11-10 00:00:00');
  75. SELECT * FROM goods;
  76. #1、序号函数
  77. #1.1、ROW_NUMBER()函数
  78. #举例1:查询 goods 数据表中每个商品分类下价格降序排列的各个商品信息。
  79. SELECT ROW_NUMBER() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
  80. id, category_id, category, NAME, price, stock
  81. FROM goods;
  82. #举例2:查询 goods 数据表中每个商品分类下价格最高的3种商品信息。
  83. SELECT *
  84. FROM (SELECT ROW_NUMBER() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
  85. id, category_id, category, NAME, price, stock
  86. FROM goods) t
  87. WHERE row_num <= 3;
  88. #1.2、RANK()函数
  89. #举例1:使用RANK()函数获取 goods 数据表中各类别的价格从高到低排序的各商品信息。
  90. SELECT RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
  91. id, category_id, category, NAME, price, stock
  92. FROM goods;
  93. #举例2:使用RANK()函数获取 goods 数据表中类别为“女装/女士精品”的价格最高的4款商品信息。
  94. SELECT *
  95. FROM(
  96. SELECT RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
  97. id, category_id, category, NAME, price, stock
  98. FROM goods) t
  99. WHERE category_id = 1 AND row_num <= 4;
  100. #1.3、DENSE_RANK()函数
  101. #举例1:使用DENSE_RANK()函数获取 goods 数据表中各类别的价格从高到低排序的各商品信息。
  102. SELECT DENSE_RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
  103. id, category_id, category, NAME, price, stock
  104. FROM goods;
  105. #举例2:使用DENSE_RANK()函数获取 goods 数据表中类别为“女装/女士精品”的价格最高的4款商品信息。
  106. SELECT *
  107. FROM(
  108. SELECT DENSE_RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
  109. id, category_id, category, NAME, price, stock
  110. FROM goods) t
  111. WHERE category_id = 1 AND row_num <= 3;
  112. #2、分布函数
  113. #2.1、PERCENT_RANK()函数
  114. #举例:计算 goods 数据表中名称为“女装/女士精品”的类别下的商品的PERCENT_RANK值。
  115. #写法一:
  116. SELECT RANK() OVER w AS r,
  117. PERCENT_RANK() OVER w AS pr,
  118. id, category_id, category, NAME, price, stock
  119. FROM goods
  120. WHERE category_id = 1 WINDOW w AS (PARTITION BY category_id ORDER BY price DESC);
  121. #写法二:
  122. SELECT RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS r,
  123. PERCENT_RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS pr,
  124. id, category_id, category, NAME, price, stock
  125. FROM goods
  126. WHERE category_id = 1;
  127. #2.2、CUME_DIST()函数
  128. #举例:查询goods数据表中小于或等于当前价格的比例。
  129. SELECT CUME_DIST() OVER(PARTITION BY category_id ORDER BY price ASC) AS cd,
  130. id, category, NAME, price
  131. FROM goods;
  132. #3、前后函数
  133. #3.1、LAG(expr,n)函数
  134. #举例:查询goods数据表中前一个商品价格与当前商品价格的差值。
  135. SELECT id, category, NAME, price, pre_price, price - pre_price AS diff_price
  136. FROM (
  137. SELECT id, category, NAME, price,LAG(price,1) OVER w AS pre_price
  138. FROM goods
  139. WINDOW w AS (PARTITION BY category_id ORDER BY price)) t;
  140. #其中,子查询如下:
  141. SELECT id, category, NAME, price,LAG(price,1) OVER (PARTITION BY category_id ORDER BY price) AS pre_price
  142. FROM goods;
  143. #3.2、LEAD(expr,n)函数
  144. #举例:查询goods数据表中后一个商品价格与当前商品价格的差值。
  145. SELECT id, category, NAME, behind_price, price,behind_price - price AS diff_price
  146. FROM(
  147. SELECT id, category, NAME, price,LEAD(price, 1) OVER w AS behind_price
  148. FROM goods WINDOW w AS (PARTITION BY category_id ORDER BY price)) t;
  149. #其中,子查询为:
  150. SELECT id, category, NAME, price,LEAD(price, 1) OVER (PARTITION BY category_id ORDER BY price) AS behind_price
  151. FROM goods;
  152. #4、首尾函数
  153. #4.1、FIRST_VALUE(expr)函数
  154. #举例:按照价格排序,查询第1个商品的价格信息。
  155. SELECT id, category, NAME, price, stock,FIRST_VALUE(price) OVER w AS first_price
  156. FROM goods WINDOW w AS (PARTITION BY category_id ORDER BY price);
  157. #4.2、LAST_VALUE(expr)函数
  158. SELECT id, category, NAME, price, stock,LAST_VALUE(price) OVER w AS last_price
  159. FROM goods WINDOW w AS (PARTITION BY category_id ORDER BY price);
  160. #5、其他函数
  161. #5.1、NTH_VALUE(expr,n)函数
  162. #举例:查询goods数据表中排名第2和第3的价格信息。
  163. SELECT id, category,NAME,price,
  164. NTH_VALUE(price,2) OVER w AS second_price,
  165. NTH_VALUE(price,3) OVER w AS third_price
  166. FROM goods WINDOW w AS (PARTITION BY category_id ORDER BY price);
  167. #5.2、NTILE(n)函数
  168. #举例:将goods表中的商品按照价格分为3组。
  169. SELECT NTILE(3) OVER w AS nt,id, category, NAME, price
  170. FROM goods WINDOW w AS (PARTITION BY category_id ORDER BY price);
  171. #二、新特性2:公用表表达式
  172. #2.1、普通公用表表达式
  173. #举例:查询员工所在的部门的详细信息。
  174. #准备工作
  175. CREATE TABLE departments
  176. AS
  177. SELECT * FROM atguigudb.departments;
  178. #子查询实现
  179. SELECT * FROM departments
  180. WHERE department_id IN (
  181. SELECT DISTINCT department_id
  182. FROM employees
  183. );
  184. #CTE实现
  185. WITH cte_emp
  186. AS (SELECT DISTINCT department_id FROM employees)
  187. SELECT *
  188. FROM departments d JOIN cte_emp e
  189. ON d.department_id = e.department_id;
  190. #2.2、递归公用表表达式
  191. #举例:找出公司employees表中所有的下下属。
  192. WITH RECURSIVE cte
  193. AS
  194. (
  195. SELECT employee_id,last_name,manager_id,1 AS n FROM employees WHERE employee_id = 100 -- 种子查询,找到第一代领导
  196. UNION ALL
  197. SELECT a.employee_id,a.last_name,a.manager_id,n+1 FROM employees AS a JOIN cte
  198. ON (a.manager_id = cte.employee_id) -- 递归查询,找出以递归公用表表达式的人为领导的人
  199. )
  200. SELECT employee_id,last_name FROM cte WHERE n >= 3;