10)mysql高级SQL语句

视图(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)
  1. mysql8.0之后版本才可以使用,一般用来代替子查询,性能和可读性都优于子查询
  2. CTE生成1个命名临时表,并只在查询期间有效
  3. 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     : 对分组后的结果进行编号,升序或降序

可以作为窗口函数的函数

  1. 聚合函数 : 聚合函数都可以作为窗口函数使用,如count(),avg(),min(),sum()等等
  2. ROW_NUMBER() : 返回窗口函数分区内数据的行号
  3. RANK() : 类似row_number,只是对相同的数据会产生重复的行号,之后的数据行号会产生间隔
  4. 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%  
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容