视图(Views)
视图是可视化的表
在sql中,视图是基于sql语句的结果集的可视化表
视图包含行和列,像一个真实的表,数据来自1个或多个数据库表中的真实字段
可以向视图添加sql函数,where,join语句,也可以呈现数据
视图总是显示最新的数据,每当用户查询视图时,数据库引擎通过sql语句重建数据
创建视图语法
CREATE VIEW view_name
AS
SELECT column_name(s)
FROM table_name
WHERE condition
示例
-- 创建视图
CREATE VIEW vm_course
AS
SELECT a.course_id,a.titl`vm_course`e,b.class_name,c.type_name,d.level_name
FROM imc_course a
JOIN imc_class b ON b.`class_id`=a.`class_id`
JOIN imc_type c ON c.type_id=a.type_id
JOIN imc_level d ON d.level_id=a.level_id;
-- 查询视图
SELECT * FROM vm_course;
-- 加过滤条件
SELECT * FROM vm_course WHERE course_id < 10;
撤销视图
DROP VIEW view_name
- 公共表达式CTE(Common Table Expression)
- mysql8.0之后版本才可以使用,一般用来代替子查询,性能和可读性都优于子查询
- CTE生成1个命名临时表,并只在查询期间有效
- CTE临时表在一个查询中可以多次引用以及自引用
CTE基础语法
WITH [ RECURSIVE ]
cte-name [ (column_list) ] AS (
query
)
[ , cte_name [ (column_list) ] AS (
query
)]
SELECT * FROM cte_name;
RECURSIVE: 循环,表明这个表可以自引用
cte_name: 表名
column_list: 列定义
query: query的结果就是临时表中的数据
可以同时定义多个公共表,每个表之间用逗号隔开
注意:query的出来的列数必须和 column_list 中的列相同,
如果省略column_list,将使用query的列作为列定义
示例
-- 最简单的公共表达式
WITH cte AS (
SELECT title,study_cnt,class_id
FROM imc_course
WHERE study_cnt>2000
)
SELECT * FROM cte
UNION ALL
SELECT * FROM cte -- 子查询是不可以多次引用的
ORDER BY title
输出
title study_cnt class_id
---------------------- --------- ----------
MySQL课程-04045 6646 2
MySQL课程-04045 6646 2
MySQL课程-04097 5245 5
MySQL课程-04097 5245 5
-- cte生成递归序列
WITH RECURSIVE cte_name AS (
SELECT 1 AS n
UNION
SELECT 1+n FROM cte_name WHERE n < 5
)
SELECT *
FROM cte_name
输出
n
--------
1
2
3
4
5
-- 递归查询出课程的评论信息,例如课程查课程59的评论
WITH RECURSIVE replay(quest_id,quest_title,user_id,replyid,path) -- 参数列表
AS (
SELECT quest_id,quest_title,user_id,replyid,CAST(quest_id AS CHAR(200)) AS path
FROM imc_question
WHERE course_id=59 AND replyid=0 -- replyid==0说明该评论是根评论
UNION ALL
SELECT a.quest_id,a.quest_title,a.user_id,a.replyid,CONCAT(b.path,'>>',a.quest_id) AS path
FROM imc_question a
-- 递归查询出对根评论的回复,a表中的记录是b表的回复
-- 如要求2320得2257的path,故只会先求2257再求2320
JOIN replay b ON a.replyid=b.quest_id
)
SELECT *
FROM replay
输出
quest_id quest_title user_id replyid path
-------- ---------------------------------------------------------------------------------------- ------- ------- ------------------
1379 用户:2214关于 MySQL课程-98454第 10章第 2节的问答 2214 0 1379
1393 用户:2214关于 MySQL课程-98454第 9章第 2节的问答 2214 0 1393
1471 用户:324关于 MySQL课程-98454第 4章第 2节的问答 324 0 1471
1585 用户:3002关于 MySQL课程-98454第 14章第 2节的问答 3002 0 1585
1591 用户:1083关于 MySQL课程-98454第 6章第 8节的问答 1083 0 1591
1760 用户:1083关于 MySQL课程-98454第 3章第 2节的问答 1083 0 1760
1794 用户:4166关于 MySQL课程-98454第 12章第 11节的评论 4166 0 1794
1827 用户:324关于 MySQL课程-98454第 1章第 4节的问答 324 0 1827
1866 用户:3002关于 MySQL课程-98454第 15章第 1节的评论 3002 0 1866
1888 用户:324关于 MySQL课程-98454第 11章第 6节的问答 324 0 1888
2246 用户:2991对于 用户:324关于 MySQL课程-98454第 4章第 2节的问答的回复 2991 1471 1471>>2246
2257 用户:2832对于 用户:2214关于 MySQL课程-98454第 10章第 2节的问答的回复 2832 1379 1379>>2257
2320 用户:2476对于 用户:2832对于 用户:2214关于 MySQL课程-98454第 10章第 2476 2257 1379>>2257>>2320
- 窗口函数
窗口函数是mysql8.0之后新增的功能,常用来对数据进行分组排序,比如成绩排名,各个类别的排名等等
窗口函数
function_name( [exp] )
OVER(
[ PARTITION BY exp [, ...] ]
[ ORDER BY exp [ ASC | DESC ] [, ...] ]
)
PARTITION BY : 对结果进行分组
ORDER BY : 对分组后的结果进行编号,升序或降序
可以作为窗口函数的函数
- 聚合函数 : 聚合函数都可以作为窗口函数使用,如count(),avg(),min(),sum()等等
- ROW_NUMBER() : 返回窗口函数分区内数据的行号
- RANK() : 类似row_number,只是对相同的数据会产生重复的行号,之后的数据行号会产生间隔
- DENSE_RANK() : 类似rank,区别在于组内数据重复时,行号会重复,但后续的行号不会产生间隔
示例
'row_number,rank,dense_rank之间的区别'
WITH test(study_name,class_name,score) AS (
SELECT 'sqlercn','mysql',95
UNION ALL
SELECT 'tom','mysql',99
UNION ALL
SELECT 'jerry','mysql',98
UNION ALL
SELECT 'gavin','mysql',98
UNION ALL
SELECT 'sqlercn','postgresql',99
UNION ALL
SELECT 'jerry','postgresql',98
)
SELECT study_name,class_name,score
,ROW_NUMBER() OVER(PARTITION BY class_name ORDER BY score DESC) AS rw
,RANK() OVER(PARTITION BY class_name ORDER BY score DESC) AS rk
,DENSE_RANK() OVER(PARTITION BY class_name ORDER BY score DESC) AS drk
FROM test
ORDER BY class_name,rw
输出
study_name class_name score rw rk drk
---------- ---------- ------ ------ ------ --------
tom mysql 99 1 1 1
jerry mysql 98 2 2 2
gavin mysql 98 3 2 2
sqlercn mysql 95 4 4 3
sqlercn postgresql 99 1 1 1
jerry postgresql 98 2 2 2
'按学习人数对课程进行排名,
并列出每类课程学习人数排名前3的课程名称,学习人数以及名次'
WITH tmp AS (
SELECT class_name,title,score
,RANK()OVER(PARTITION BY class_name ORDER BY score DESC) AS cnt
FROM imc_course a
JOIN imc_class b ON b.class_id=a.class_id
)
SELECT *
FROM tmp WHERE cnt<=3
输出
class_name title score cnt
--------------- ---------------------- ------ --------
Docker MySQL课程-57732 9.8 1
Docker SQLServer课程-90092 9.8 1
Docker PostgreSQL课程-27822 9.7 3
HadoopDock SQLServer课程-52859 9.8 1
HadoopDock PostgreSQL课程-71352 9.8 1
HadoopDock PostgreSQL课程-00924 9.4 3
Hbase MySQL课程-69546 9.9 1
Hbase PostgreSQL课程-90898 9.9 1
Hbase PostgreSQL课程-87282 9.8 3
'每门课程的学习人数占本类课程总学习人数的百分比'
WITH tmp AS (
SELECT class_name,title,study_cnt
,SUM(study_cnt) OVER(PARTITION BY class_name) AS class_total
FROM imc_course a
JOIN imc_class b ON b.class_id=a.class_id
)
SELECT class_name,title,CONCAT(study_cnt/class_total*100,'%')
FROM tmp
ORDER BY class_name
输出
class_name title CONCAT(study_cnt/class_total*100,'%')
--------------- ---------------------- ---------------------------------------
Docker SQLServer课程-90092 19.6756%
Docker PostgreSQL课程-85484 8.9576%
Docker PostgreSQL课程-33460 27.6694%
Docker SQLServer课程-41163 18.0422%
Docker PostgreSQL课程-55484 1.5901%
Docker SQLServer课程-60895 13.2316%
Docker PostgreSQL课程-27822 0.5541%
Docker MySQL课程-57732 10.2793%
HadoopDock PostgreSQL课程-00924 17.5546%
HadoopDock SQLServer课程-63911 6.8858%
HadoopDock SQLServer课程-52859 16.1480%
HadoopDock SQLServer课程-06325 1.3606%
HadoopDock PostgreSQL课程-71352 28.0395%
HadoopDock SQLServer课程-09426 30.0115%