Compare commits
	
		
			2 Commits
		
	
	
		
			1ed786139f
			...
			cb02a70fcf
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						cb02a70fcf
	
				 | 
					
					
						|||
| 
						
						
							
						
						98b3779e63
	
				 | 
					
					
						
							
								
								
									
										458
									
								
								SQL-窗口函数.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										458
									
								
								SQL-窗口函数.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,458 @@
 | 
				
			|||||||
 | 
					# SQL窗口函数
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 一. 什么是窗口函数
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 基本含义
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					窗口限定一个范围,它可以理解为满足某些条件的记录集合,窗口函数也就是在窗口范围内执行的函数。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 基本语法
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					窗口函数有over关键字,指定函数执行的范围,可分为三部分:分组子句(partition by),排序子句(order by),窗口子句(rows)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					<函数名> over (partition by <分组的列> order by <排序的列> rows between <起始行> and <终止行>)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**注意Mysql8才支持窗口函数**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 演示表格
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| cid(班级id) | sname(学生姓名) | score(分数) |
 | 
				
			||||||
 | 
					| ------------ | ----------------- | ------------- |
 | 
				
			||||||
 | 
					| 001          | 张三              | 78            |
 | 
				
			||||||
 | 
					| 001          | 李四              | 82            |
 | 
				
			||||||
 | 
					| 002          | 小明              | 90            |
 | 
				
			||||||
 | 
					| 001          | 王五              | 67            |
 | 
				
			||||||
 | 
					| 002          | 小红              | 85            |
 | 
				
			||||||
 | 
					| 002          | 小刚              | 62            |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 演示脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					CREATE TABLE SQL_5 (
 | 
				
			||||||
 | 
					       cid varchar(4),
 | 
				
			||||||
 | 
					       sname varchar(4),
 | 
				
			||||||
 | 
					       score int
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into SQL_5 (cid, sname, score) values ('001', '张三', 78);
 | 
				
			||||||
 | 
					insert into SQL_5 (cid, sname, score) values ('001', '李四', 82);
 | 
				
			||||||
 | 
					insert into SQL_5 (cid, sname, score) values ('002', '小明', 90);
 | 
				
			||||||
 | 
					insert into SQL_5 (cid, sname, score) values ('001', '王五', 67);
 | 
				
			||||||
 | 
					insert into SQL_5 (cid, sname, score) values ('002', '小红', 85);
 | 
				
			||||||
 | 
					insert into SQL_5 (cid, sname, score) values ('002', '小刚', 62);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 二. 窗口的确定
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					例子:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select *, sum(score) over (partition by cid order by score rows between unbounded preceding and unbounded following) as '班级总分' from SQL_5;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 分组子句(partition by)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					不分组可以写成partition by null或者直接不写
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					后面可以跟多个列, 如 partition by cid, sname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**注意 partition by与group by的区别**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1)前者不会压缩行数但是后者会
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2)后者只能选取分组的列和聚合的列
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					也就是说group by 后生成的结果集与原表的行数和列数都不同
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 排序子句(order by)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					不排序可以写成order by null 或者直接不写
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					asc或不写表示升序,desc表示降序
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					后面可以跟多个列, 如 order by cid, sname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 窗口子句(rows)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					窗口子句的描述
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1) 起始行:   N preceding/unbounded preceding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2) 当前行:   current row
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3) 终止行:   N following/unbounded following
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					举例:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rows between unbounded  preceding and current row  从之前所有的行到当前行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rows between 2 preceding and current row  从前面两行到当前行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rows between current row and unbounded following  从当前行到之后所有的行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rows between current row and 1following  从当前行到后面一行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**注意:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**排序子句后面缺少窗口子句,窗口规范默认是 rows between unbounded preceding and current row**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**排序子句和窗口子句都缺失,窗口规范默认是 rows between unbounded preceding and unbounded following**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 总体流程
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1) 通过partition by 和 order by 子句确定大窗口( 定义出上界unbounded preceding和下界unbounded following)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2) 通过row 子句针对每一行数据确定小窗口(滑动窗口)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3) 对每行的小窗口内的数据执行函数并生成新的列
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 三. 函数分类
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 排序类
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rank, dense_rank, row_number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					-- 【排序类】
 | 
				
			||||||
 | 
					-- 按班级分组后打上序号 不考虑并列
 | 
				
			||||||
 | 
					select *, row_number() over (partition by cid order by score desc) as '不可并列排名' from SQL_5;
 | 
				
			||||||
 | 
					-- 按班级分组后作跳跃排名 考虑并列
 | 
				
			||||||
 | 
					select *, rank() over (partition by cid order by score desc) as '跳跃可并列排名' from SQL_5;
 | 
				
			||||||
 | 
					-- 按班级分组后作连续排名 考虑并列
 | 
				
			||||||
 | 
					select *, dense_rank() over (partition by cid order by score desc) as '连续可并列排名' from SQL_5;
 | 
				
			||||||
 | 
					-- 合并起来对比
 | 
				
			||||||
 | 
					select *, row_number() over (partition by cid order by score desc) as '不可并列排名' ,
 | 
				
			||||||
 | 
					          rank() over (partition by cid order by score desc) as '跳跃可并列排名',
 | 
				
			||||||
 | 
					          dense_rank() over (partition by cid order by score desc) as '连续可并列排名'
 | 
				
			||||||
 | 
					from SQL_5;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 聚合类
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sum. avg, count, max, min
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					-- 【聚合类】
 | 
				
			||||||
 | 
					-- 让同一班级每个学生都知道班级总分是多少
 | 
				
			||||||
 | 
					select *, sum(score) over (partition by cid) as '班级总分' from SQL_5;
 | 
				
			||||||
 | 
					-- 或者可以写成
 | 
				
			||||||
 | 
					select *, sum(score) over (partition by cid rows between unbounded preceding and unbounded following) as '班级总分' from SQL_5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- 计算同一班级,每个同学和比他分数低的同学的累计总分是多少
 | 
				
			||||||
 | 
					select *, sum(score) over (partition by cid order by score) '累加分数' from SQL_5;
 | 
				
			||||||
 | 
					-- 或者可以写成 其中rows between ... and 是规定窗口大小
 | 
				
			||||||
 | 
					select *, sum(score) over (partition by cid order by score rows between unbounded preceding and current row) as '累加分数' from SQL_5;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 跨行类
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lag, lead
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					-- 【跨行类】
 | 
				
			||||||
 | 
					-- lag/lead 函数 参数1:比较的列 参数2: 偏移量 参数3:找不到的默认值
 | 
				
			||||||
 | 
					-- 同一班级内,成绩比自己低一名的分数是多少
 | 
				
			||||||
 | 
					select *, lag(score, 1) over (partition by cid order by score) as '低一名的分数' from SQL_5;
 | 
				
			||||||
 | 
					-- 或者写成
 | 
				
			||||||
 | 
					select *, lag(score, 1, 0) over (partition by cid order by score) as '低一名的分数' from SQL_5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- 同一班级内,成绩比自己高2名的分数是多少
 | 
				
			||||||
 | 
					select *, lead(score, 2) over (partition by cid order by score) as '高两名的分数' from SQL_5;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 四. 相关题目
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 表格
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| cid  | sname | course | score |
 | 
				
			||||||
 | 
					| ---- | ----- | ------ | ----- |
 | 
				
			||||||
 | 
					| 001  | 张三  | 语文   | 78    |
 | 
				
			||||||
 | 
					| 002  | 小刚  | 语文   | 71    |
 | 
				
			||||||
 | 
					| 001  | 李四  | 数学   | 56    |
 | 
				
			||||||
 | 
					| 002  | 小明  | 数学   | 54    |
 | 
				
			||||||
 | 
					| ...  | ...   | ...    | ...   |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					CREATE TABLE SQL_6 (
 | 
				
			||||||
 | 
					       cid varchar(4),
 | 
				
			||||||
 | 
					       sname varchar(4),
 | 
				
			||||||
 | 
					       course varchar(10),
 | 
				
			||||||
 | 
					       score int
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '张三', '语文', 78);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小刚', '语文', 71);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '李四', '数学', 56);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '王五', '数学', 97);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小明', '数学', 54);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小刚', '数学', 67);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小红', '数学', 82);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '王五', '语文', 80);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '张三', '数学', 77);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小明', '语文', 58);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小红', '语文', 87);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '李四', '语文', 60);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '张三', '英语', 66);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小刚', '英语', 50);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '李四', '地理', 59);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '王五', '地理', 88);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小明', '地理', 45);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小刚', '地理', 66);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小红', '地理', 82);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '王五', '英语', 81);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '张三', '地理', 77);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小明', '英语', 55);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('002', '小红', '英语', 87);
 | 
				
			||||||
 | 
					insert into SQL_6 (cid, sname, course, score) values ('001', '李四', '英语', 61);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 分组内topN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					问题1:求出每个学生成绩最高的三条记录
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select * from 
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    select *, row_number() over (partition by sname order by score desc) as rn from SQL_6   
 | 
				
			||||||
 | 
					) temp
 | 
				
			||||||
 | 
					where rn <= 3
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###### 公式:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select * from
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
						select *, row_number() over (partition by 分组列 order by 比较列) as rn from table
 | 
				
			||||||
 | 
					) as tmp
 | 
				
			||||||
 | 
					where rn <= N;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 汇总分析
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					问题2:找出每门课程都高于班级课程平均分的学生
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					可以拆解成以下几个问题:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1)求出每个班级,每门课程的平均分
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					with
 | 
				
			||||||
 | 
					-- 1) 求出每个班级,每门课程的平均分
 | 
				
			||||||
 | 
					t1 as
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					select *,
 | 
				
			||||||
 | 
					       avg(score) over (partition by cid, course) as 'avg'
 | 
				
			||||||
 | 
					from SQL_6
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2)将学生每门课程的成绩与所在班级的对应课程平均分相减,结果大于0就说明该学生的这门成绩高于课程平均分
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					t2 as (
 | 
				
			||||||
 | 
					    select *,
 | 
				
			||||||
 | 
					           score - avg  as 'del'
 | 
				
			||||||
 | 
					    from t1
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3)“找出每门课程都高于班级课程平均分的学生”说明对于学生来说,最小的“相减结果”都是大于0的
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select sname from t2
 | 
				
			||||||
 | 
					group by sname
 | 
				
			||||||
 | 
					having min(del) > 0;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					合并后的SQL语句
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					with
 | 
				
			||||||
 | 
					t1 as
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					select *,
 | 
				
			||||||
 | 
					       avg(score) over (partition by cid, course) as 'avg'
 | 
				
			||||||
 | 
					from SQL_6
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					t2 as (
 | 
				
			||||||
 | 
					    select *,
 | 
				
			||||||
 | 
					           score - avg  as 'del'
 | 
				
			||||||
 | 
					    from t1
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					select sname from t2
 | 
				
			||||||
 | 
					group by sname
 | 
				
			||||||
 | 
					having min(del) > 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- 或者
 | 
				
			||||||
 | 
					select sname from (
 | 
				
			||||||
 | 
					                      select *,
 | 
				
			||||||
 | 
					                             score - avg  as 'del'
 | 
				
			||||||
 | 
					                      from (
 | 
				
			||||||
 | 
					                               select *,
 | 
				
			||||||
 | 
					                                      avg(score) over (partition by cid, course) as 'avg'
 | 
				
			||||||
 | 
					                               from SQL_6
 | 
				
			||||||
 | 
					                           ) t1
 | 
				
			||||||
 | 
					                  ) t2
 | 
				
			||||||
 | 
					group by sname
 | 
				
			||||||
 | 
					having min(del) > 0;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 表格
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| empno | ename | hire_date  | salary | dept_no |
 | 
				
			||||||
 | 
					| ----- | ----- | ---------- | ------ | ------- |
 | 
				
			||||||
 | 
					| 001   | Adam  | 2018-03-01 | 1000   | A       |
 | 
				
			||||||
 | 
					| 002   | Bill  | 2021-03-01 | 1200   | A       |
 | 
				
			||||||
 | 
					| 003   | Cindy | 2016-03-01 | 1500   | A       |
 | 
				
			||||||
 | 
					| 004   | Danny | 2020-03-01 | 5000   | A       |
 | 
				
			||||||
 | 
					| 005   | Eason | 2020-03-01 | 4000   | B       |
 | 
				
			||||||
 | 
					| 006   | Fred  | 2018-03-01 | 3500   | B       |
 | 
				
			||||||
 | 
					| 007   | Gary  | 2017-03-01 | 1800   | B       |
 | 
				
			||||||
 | 
					| 008   | Hugo  | 2020-03-01 | 2500   | B       |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					CREATE TABLE SQL_7 (
 | 
				
			||||||
 | 
					       empno varchar(4),
 | 
				
			||||||
 | 
					       ename varchar(10),
 | 
				
			||||||
 | 
					       hire_date varchar(10),
 | 
				
			||||||
 | 
					       salary int,
 | 
				
			||||||
 | 
					       dept_no varchar(2)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					insert into SQL_7 (empno, ename, hire_date, salary, dept_no) values ('001', 'Adam', '2018-03-01', 1000, 'A');
 | 
				
			||||||
 | 
					insert into SQL_7 (empno, ename, hire_date, salary, dept_no) values ('002', 'Bill', '2021-03-01', 1200, 'A');
 | 
				
			||||||
 | 
					insert into SQL_7 (empno, ename, hire_date, salary, dept_no) values ('003', 'Cindy', '2016-03-01', 1500, 'A');
 | 
				
			||||||
 | 
					insert into SQL_7 (empno, ename, hire_date, salary, dept_no) values ('004', 'Danny', '2020-03-01', 5000, 'A');
 | 
				
			||||||
 | 
					insert into SQL_7 (empno, ename, hire_date, salary, dept_no) values ('005', 'Eason', '2020-03-01', 4000, 'B');
 | 
				
			||||||
 | 
					insert into SQL_7 (empno, ename, hire_date, salary, dept_no) values ('006', 'Fred', '2018-03-01', 3500, 'B');
 | 
				
			||||||
 | 
					insert into SQL_7 (empno, ename, hire_date, salary, dept_no) values ('007', 'Gary', '2017-03-01', 1800, 'B');
 | 
				
			||||||
 | 
					insert into SQL_7 (empno, ename, hire_date, salary, dept_no) values ('008', 'Hugo', '2020-03-01', 4500, 'B');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select * from SQL_7;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 分组内topN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					问题一:求出每个部门工资最高的前三名员工
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select * from
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					        select *, row_number() over (partition by dept_no order by salary desc) as rn from SQL_7
 | 
				
			||||||
 | 
					    ) as tmp
 | 
				
			||||||
 | 
					where rn <= 3;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 汇总分析
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					问题二:计算这些员工的工资占所属部门总工资的百分比
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					with
 | 
				
			||||||
 | 
					t1 as (
 | 
				
			||||||
 | 
					    select * , sum(salary) over (partition by dept_no) as 'sum_sal' from SQL_7
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					t2 as (
 | 
				
			||||||
 | 
					    select *, round(salary*100/sum_sal,2) as 'percentage' from t1
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					select * from t2;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					问题三:对各部门员工的工资进行从小到大排序,排名前30%为低层,30%-80%为中层,高于80%为高层,并打上标签
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```label
 | 
				
			||||||
 | 
					with
 | 
				
			||||||
 | 
					    t1 as (
 | 
				
			||||||
 | 
					        select * , row_number() over (partition by dept_no order by salary) as cnt,
 | 
				
			||||||
 | 
					               count(empno) over (partition by dept_no) as 'sum' from SQL_7
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    t2 as (
 | 
				
			||||||
 | 
					        select *, round(cnt/sum,2) as 'percentage' from t1
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    t3 as (
 | 
				
			||||||
 | 
					        select *, case when percentage <= 0.3 then '低层'
 | 
				
			||||||
 | 
					                       when percentage <= 0.8 then '中层'
 | 
				
			||||||
 | 
					                       when percentage <= 1 then '高层' end as 'label'
 | 
				
			||||||
 | 
					        from t2
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					select empno, ename, hire_date, salary, dept_no, label from t3;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					问题四:统计每年入职总数以及截至本年累计入职总人数(本年总入职人数 + 本年之前所有年的总入职人数之和)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select year(hire_date) as hire_year, count(empno) as cnt
 | 
				
			||||||
 | 
					    from SQL_7
 | 
				
			||||||
 | 
					    group by year(hire_date) order by hire_year;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					with t1 as (
 | 
				
			||||||
 | 
					    select year(hire_date) as hire_year, count(empno) as cnt from SQL_7 group by year(hire_date) order by hire_year
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select *, sum(cnt) over(partition by null rows between unbounded preceding and current row) as sum from t1;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 五. 技巧
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1)分组内topN公式
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select * from
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
						select *, row_number() over (partition by 分组列 order by 比较列) as rn from table
 | 
				
			||||||
 | 
					) as tmp
 | 
				
			||||||
 | 
					where rn <= N;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2) 窗口函数 -> 生成辅助列(相当于高级语言的临时变量)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3)   with 语句 -> 生成临时表(相当于高级语言的局部方法)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       把复杂的问题拆分成多个子问题并用临时表去表达
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										324
									
								
								SQL-行转列与列转行.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								SQL-行转列与列转行.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,324 @@
 | 
				
			|||||||
 | 
					# SQL 讲解 —— 行转列 与 列转行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 行转列
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 题目1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 描述
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					name  subject  score
 | 
				
			||||||
 | 
					张三    语文     78
 | 
				
			||||||
 | 
					张三    数学     88
 | 
				
			||||||
 | 
					张三    英语 	 98
 | 
				
			||||||
 | 
					李四    语文     89
 | 
				
			||||||
 | 
					李四    数学     76
 | 
				
			||||||
 | 
					李四    英语     90
 | 
				
			||||||
 | 
					王五    语文	 99
 | 
				
			||||||
 | 
					王五	  数学	 66
 | 
				
			||||||
 | 
					王五	  英语	 91
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					name  语文  数学  英语
 | 
				
			||||||
 | 
					张三   78   88    98
 | 
				
			||||||
 | 
					李四   89   76    90
 | 
				
			||||||
 | 
					王五   99   66    91
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					create table SQL_1
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    name varchar(20),
 | 
				
			||||||
 | 
					    subject varchar(20),
 | 
				
			||||||
 | 
					    score float
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					insert into SQL_1 (name, subject, score) values ('张三', '语文', 78);
 | 
				
			||||||
 | 
					insert into SQL_1 (name, subject, score) values ('张三', '数学', 88);
 | 
				
			||||||
 | 
					insert into SQL_1 (name, subject, score) values ('张三', '英语', 98);
 | 
				
			||||||
 | 
					insert into SQL_1 (name, subject, score) values ('李四', '语文', 89);
 | 
				
			||||||
 | 
					insert into SQL_1 (name, subject, score) values ('李四', '数学', 76);
 | 
				
			||||||
 | 
					insert into SQL_1 (name, subject, score) values ('李四', '英语', 90);
 | 
				
			||||||
 | 
					insert into SQL_1 (name, subject, score) values ('王五', '语文', 99);
 | 
				
			||||||
 | 
					insert into SQL_1 (name, subject, score) values ('王五', '数学', 66);
 | 
				
			||||||
 | 
					insert into SQL_1 (name, subject, score) values ('王五', '英语', 91);
 | 
				
			||||||
 | 
					select * from SQL_1;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 解题步骤
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1) 确定分组列,转换列,数据列
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2) 生成伪列
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3) 做分组查询
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4) 选择合适的聚合函数
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 两步法
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 公式:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select 分组列,
 | 
				
			||||||
 | 
					       聚合函数(m1) as 列名1,
 | 
				
			||||||
 | 
					       聚合函数(m2) as 列名2,
 | 
				
			||||||
 | 
					       聚合函数(m3) as 列名3
 | 
				
			||||||
 | 
					from (select *,
 | 
				
			||||||
 | 
					             case 转换列 when 转换列值1 then 数据列 else ... end as m1,
 | 
				
			||||||
 | 
					             case 转换列 when 转换列值2 then 数据列 else ... end as m2,
 | 
				
			||||||
 | 
					             case 转换列 when 转换列值3 then 数据列 else ... end as m3
 | 
				
			||||||
 | 
					      from 表名) 临时表名
 | 
				
			||||||
 | 
					group by 分组列;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 解题SQL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select name,
 | 
				
			||||||
 | 
					       sum(m1) as 语文,
 | 
				
			||||||
 | 
					       sum(m2) as 数学,
 | 
				
			||||||
 | 
					       sum(m3) as 英语
 | 
				
			||||||
 | 
					from (select *,
 | 
				
			||||||
 | 
					             case subject when '语文' then score else 0 end as m1,
 | 
				
			||||||
 | 
					             case subject when '数学' then score else 0 end as m2,
 | 
				
			||||||
 | 
					             case subject when '英语' then score else 0 end as m3
 | 
				
			||||||
 | 
					      from sql_1) tmp
 | 
				
			||||||
 | 
					group by name;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 一步法
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 公式:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select 分组列,
 | 
				
			||||||
 | 
					       聚合函数(case 转换列 when 转换列值1 then 数据列 else ... end) as 列名1,
 | 
				
			||||||
 | 
						   聚合函数(case 转换列 when 转换列值2 then 数据列 else ... end) as 列名2,
 | 
				
			||||||
 | 
						   聚合函数(case 转换列 when 转换列值3 then 数据列 else ... end) as 列名3
 | 
				
			||||||
 | 
						   ...
 | 
				
			||||||
 | 
					from 表名
 | 
				
			||||||
 | 
					group by 分组列;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select 分组列,
 | 
				
			||||||
 | 
					       聚合函数(case when 转换列=转换列值1 then 数据列 else ... end) as 列名1,
 | 
				
			||||||
 | 
						   聚合函数(case when 转换列=转换列值2 then 数据列 else ... end) as 列名2,
 | 
				
			||||||
 | 
						   聚合函数(case when 转换列=转换列值3 then 数据列 else ... end) as 列名3
 | 
				
			||||||
 | 
						   ...
 | 
				
			||||||
 | 
					from 表名
 | 
				
			||||||
 | 
					group by 分组列;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 解题SQL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select name,
 | 
				
			||||||
 | 
					       sum(case subject when '语文' then score else 0 end) as 语文,
 | 
				
			||||||
 | 
					       sum(case subject when '数学' then score else 0 end) as 数学,
 | 
				
			||||||
 | 
					       sum(case subject when '英语' then score else 0 end) as 英语
 | 
				
			||||||
 | 
					from sql_1
 | 
				
			||||||
 | 
					group by name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select name,
 | 
				
			||||||
 | 
					       sum(case when subject = '语文' then score else 0 end) as 语文,
 | 
				
			||||||
 | 
					       sum(case when subject = '数学' then score else 0 end) as 数学,
 | 
				
			||||||
 | 
					       sum(case when subject = '英语' then score else 0 end) as 英语
 | 
				
			||||||
 | 
					from sql_1
 | 
				
			||||||
 | 
					group by name;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 题目2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 描述
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```txt
 | 
				
			||||||
 | 
					# 日期        结果
 | 
				
			||||||
 | 
					# 2022-01-01  胜
 | 
				
			||||||
 | 
					# 2022-01-01  胜
 | 
				
			||||||
 | 
					# 2022-01-02  负
 | 
				
			||||||
 | 
					# 2022-01-02  负
 | 
				
			||||||
 | 
					# 2022-01-01  负
 | 
				
			||||||
 | 
					# 2022-01-02  负
 | 
				
			||||||
 | 
					# 2022-01-02  胜
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 日期         胜 负
 | 
				
			||||||
 | 
					# 2022-01-01  2  1
 | 
				
			||||||
 | 
					# 2022-01-02  1  3
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					create table SQL_2(
 | 
				
			||||||
 | 
					   ddate varchar(10), result varchar(2)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into SQL_2 (ddate, result) values('2022-01-01','胜');
 | 
				
			||||||
 | 
					insert into SQL_2 (ddate, result) values('2022-01-01','胜');
 | 
				
			||||||
 | 
					insert into SQL_2 (ddate, result) values('2022-01-02','负');
 | 
				
			||||||
 | 
					insert into SQL_2 (ddate, result) values('2022-01-02','负');
 | 
				
			||||||
 | 
					insert into SQL_2 (ddate, result) values('2022-01-01','负');
 | 
				
			||||||
 | 
					insert into SQL_2 (ddate, result) values('2022-01-02','负');
 | 
				
			||||||
 | 
					insert into SQL_2 (ddate, result) values('2022-01-02','胜');
 | 
				
			||||||
 | 
					select * from SQL_2;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 解题SQL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					select ddate,
 | 
				
			||||||
 | 
					       sum(case when result = '胜' then 1 else 0 end) as 胜,
 | 
				
			||||||
 | 
					       sum(case when result = '负' then 1 else 0 end) as 负
 | 
				
			||||||
 | 
					from sql_2
 | 
				
			||||||
 | 
					group by ddate;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 列转行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 题目3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 描述
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```txt
 | 
				
			||||||
 | 
					name  语文  数学  英语 
 | 
				
			||||||
 | 
					张三   78   88    98
 | 
				
			||||||
 | 
					李四   89   76    90
 | 
				
			||||||
 | 
					王五   99   66    91 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					name  subject  score
 | 
				
			||||||
 | 
					张三    语文     78
 | 
				
			||||||
 | 
					张三    数学     88
 | 
				
			||||||
 | 
					张三    英语 	 98
 | 
				
			||||||
 | 
					李四    语文     89
 | 
				
			||||||
 | 
					李四    数学     76
 | 
				
			||||||
 | 
					李四    英语     90
 | 
				
			||||||
 | 
					王五    语文	 99
 | 
				
			||||||
 | 
					王五	  数学	 66
 | 
				
			||||||
 | 
					王五	  英语	 91
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					CREATE TABLE SQL_3 (
 | 
				
			||||||
 | 
						name varchar(20),
 | 
				
			||||||
 | 
					    语文 float,
 | 
				
			||||||
 | 
					    数学 float,
 | 
				
			||||||
 | 
					    英语 float
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into SQL_3 (name, '语文', '数学', '英语') values ('张三', 78, 88, 98);
 | 
				
			||||||
 | 
					insert into SQL_3 (name, '语文', '数学', '英语') values ('李四', 89, 76, 90);
 | 
				
			||||||
 | 
					insert into SQL_3 (name, '语文', '数学', '英语') values ('王五', 99, 66, 91);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 解题步骤
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1) 确定转换列,非转换列
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2) 生成新列
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3) 使用union或union all 进行合并
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4) 根据需要进行order by
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 公式
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					SELECT 非转换列, '转换列1' AS 新转换列名, 转换列1 AS 新数据列名 FROM 表名
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					SELECT 非转换列, '转换列2' AS 新转换列名, 转换列2 AS 新数据列名 FROM 表名
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					SELECT 非转换列, '转换列3' AS 新转换列名, 转换列3 AS 新数据列名 FROM 表名
 | 
				
			||||||
 | 
					ORDER BY ...;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 解题SQL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					SELECT name,'语文' AS subject,语文 AS score FROM SQL_3
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					SELECT name,'数学' AS subject,数学 AS score FROM SQL_3
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					SELECT name,'英语' AS subject,英语 AS score FROM SQL_3
 | 
				
			||||||
 | 
					ORDER BY name ASC, subject DESC;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 题目4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 描述
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```txt
 | 
				
			||||||
 | 
					Q1     Q2     Q3     Q4
 | 
				
			||||||
 | 
					1000   2000   3000   4000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					季度   业绩
 | 
				
			||||||
 | 
					Q1    1000
 | 
				
			||||||
 | 
					Q2    2000
 | 
				
			||||||
 | 
					Q3    3000
 | 
				
			||||||
 | 
					Q4    4000
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					CREATE TABLE SQL_4 (
 | 
				
			||||||
 | 
						Q1 int, Q2 int, Q3 int, Q4 int
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into SQL_4 values (1000, 2000, 3000, 4000);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 解题SQL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					SELECT  'Q1' AS 季度, Q1 AS 业绩 FROM SQL_4
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					SELECT 'Q2' AS 季度, Q2 AS 业绩 FROM SQL_4
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					SELECT 'Q3' AS 季度, Q3 AS 业绩 FROM SQL_4
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					SELECT 'Q4' AS 季度, Q4 AS 业绩 FROM SQL_4
 | 
				
			||||||
 | 
					ORDER BY 季度;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 技巧:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					扩展列:select ... as 新列名
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					减少列:直接不写
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					扩展行:union/ union all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					减少行:  聚合函数
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										231
									
								
								SQL窗口函数(二).md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								SQL窗口函数(二).md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,231 @@
 | 
				
			|||||||
 | 
					# SQL窗口函数(二)—— 连续问题
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 题目一
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 表格
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| user_id | login_date |
 | 
				
			||||||
 | 
					| ------- | ---------- |
 | 
				
			||||||
 | 
					| A       | 2022-09-02 |
 | 
				
			||||||
 | 
					| A       | 2022-09-03 |
 | 
				
			||||||
 | 
					| A       | 2022-09-04 |
 | 
				
			||||||
 | 
					| B       | 2021-11-25 |
 | 
				
			||||||
 | 
					| B       | 2021-12-31 |
 | 
				
			||||||
 | 
					| C       | 2022-01-01 |
 | 
				
			||||||
 | 
					| C       | 2022-04-04 |
 | 
				
			||||||
 | 
					| C       | 2022-09-03 |
 | 
				
			||||||
 | 
					| C       | 2022-09-04 |
 | 
				
			||||||
 | 
					| C       | 2022-09-05 |
 | 
				
			||||||
 | 
					| A       | 2022-09-03 |
 | 
				
			||||||
 | 
					| D       | 2022-10-20 |
 | 
				
			||||||
 | 
					| D       | 2022-10-21 |
 | 
				
			||||||
 | 
					| A       | 2022-10-03 |
 | 
				
			||||||
 | 
					| D       | 2022-10-22 |
 | 
				
			||||||
 | 
					| D       | 2022-10-23 |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					CREATE TABLE SQL_8
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					     user_id 	varchar(2),
 | 
				
			||||||
 | 
					     login_date date
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					INSERT INTO SQL_8 (user_id,login_date)
 | 
				
			||||||
 | 
					VALUES ('A', '2022-09-02'), ('A', '2022-09-03'), ('A', '2022-09-04'), ('B', '2021-11-25'),
 | 
				
			||||||
 | 
					       ('B', '2021-12-31'), ('C', '2022-01-01'), ('C', '2022-04-04'), ('C', '2022-09-03'),
 | 
				
			||||||
 | 
					       ('C', '2022-09-05'), ('C', '2022-09-04'), ('A', '2022-09-03'), ('D', '2022-10-20'),
 | 
				
			||||||
 | 
					       ('D', '2022-10-21'), ('A', '2022-10-03'), ('D', '2022-10-22'), ('D', '2022-10-23');
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 问题
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					找出这张表中所有的连续3天登录用户
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 分析
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					连续N天登录用户,要求数据行满足以下条件:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1) userid 要相同,表示同一用户
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2) 同一用户每行记录以登录时间从小到大排序
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3) 后一行记录比前一行记录的登录时间多一天
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4) 数据行数大于等于N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 解答
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					-- 方法一
 | 
				
			||||||
 | 
					with t1 as (
 | 
				
			||||||
 | 
					    select distinct user_id, login_date from SQL_8
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					t2 as (
 | 
				
			||||||
 | 
					    select *, row_number() over (partition by user_id order by login_date) as rn from t1
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					t3 as (
 | 
				
			||||||
 | 
					    select *, DATE_SUB(login_date, interval rn day) as sub from t2
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					select distinct user_id from t3 group by user_id, sub having count(user_id) >= 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- 方法二
 | 
				
			||||||
 | 
					with t1 as (
 | 
				
			||||||
 | 
					    select distinct user_id, login_date from SQL_8
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					t2 as (
 | 
				
			||||||
 | 
					    select *, DATEDIFF(login_date, lag(login_date, 1) over (partition by user_id order by login_date)) as diff from t1
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					select user_id from t2 where diff = 1 group by user_id having count(user_id) >= 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 题目二
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 表格
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| player_id | score | score_time          |
 | 
				
			||||||
 | 
					| --------- | ----- | ------------------- |
 | 
				
			||||||
 | 
					| B3        | 1     | 2022-09-20 19:00:14 |
 | 
				
			||||||
 | 
					| A2        | 1     | 2022-09-20 19:01:04 |
 | 
				
			||||||
 | 
					| A2        | 3     | 2022-09-20 19:01:16 |
 | 
				
			||||||
 | 
					| A2        | 3     | 2022-09-20 19:02:05 |
 | 
				
			||||||
 | 
					| A2        | 2     | 2022-09-20 19:02:25 |
 | 
				
			||||||
 | 
					| B5        | 2     | 2022-09-20 19:02:54 |
 | 
				
			||||||
 | 
					| A4        | 3     | 2022-09-20 19:03:10 |
 | 
				
			||||||
 | 
					| B1        | 2     | 2022-09-20 19:03:34 |
 | 
				
			||||||
 | 
					| B1        | 2     | 2022-09-20 19:03:58 |
 | 
				
			||||||
 | 
					| B1        | 3     | 2022-09-20 19:04:07 |
 | 
				
			||||||
 | 
					| A2        | 1     | 2022-09-20 19:04:19 |
 | 
				
			||||||
 | 
					| A3        | 2     | 2022-09-20 19:04:31 |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					CREATE TABLE SQL_9
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					     player_id 	varchar(2),
 | 
				
			||||||
 | 
					     score      int,
 | 
				
			||||||
 | 
					     score_time datetime
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					INSERT INTO SQL_9 (player_id, score, score_time)
 | 
				
			||||||
 | 
					VALUES ('B3', 1, '2022-09-20 19:00:14'), ('A2', 1, '2022-09-20 19:01:04'),
 | 
				
			||||||
 | 
					       ('A2', 3, '2022-09-20 19:01:16'), ('A2', 3, '2022-09-20 19:02:05'),
 | 
				
			||||||
 | 
					       ('A2', 2, '2022-09-20 19:02:25'), ('B3', 2, '2022-09-20 19:02:54'),
 | 
				
			||||||
 | 
					       ('A4', 3, '2022-09-20 19:03:10'), ('B1', 2, '2022-09-20 19:03:34'),
 | 
				
			||||||
 | 
					       ('B1', 2, '2022-09-20 19:03:58'), ('B1', 3, '2022-09-20 19:04:07'),
 | 
				
			||||||
 | 
					       ('A2', 1, '2022-09-20 19:04:19'), ('B3', 2, '2022-09-20 19:04:31');
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 问题
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					统计出连续三次(及以上)为球队得分的球员名单
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 分析
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					连续N次以上为球队得分, 要求数据行满足以下条件:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1) player_id 要相同表示同一球员
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2) 每行记录以得分时间从小到大排序
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3) 数据行数大于等于N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 解答
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					-- 方法一
 | 
				
			||||||
 | 
					with t1 as (
 | 
				
			||||||
 | 
					    select *, lag(player_id, 1) over (order by score_time) as last_play_id from SQL_9
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					select distinct player_id from t1 where player_id = last_play_id group by player_id having count(player_id) >= 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- 方法二
 | 
				
			||||||
 | 
					with t1 as (
 | 
				
			||||||
 | 
					    select *, row_number() over (order by score_time) as rn from SQL_9
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					 t2 as (
 | 
				
			||||||
 | 
					     select *, row_number() over (order by score_time) + 1 as rn from SQL_9
 | 
				
			||||||
 | 
					 ),
 | 
				
			||||||
 | 
					 t3 as (
 | 
				
			||||||
 | 
					     select t1.player_id  as player_id from t1 join t2 on t1.rn = t2.rn and t1.player_id = t2.player_id
 | 
				
			||||||
 | 
					 )
 | 
				
			||||||
 | 
					select distinct player_id from t3 group by player_id having count(player_id) >= 2;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 题目三
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 表格
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| log_id |
 | 
				
			||||||
 | 
					| :----: |
 | 
				
			||||||
 | 
					|   1    |
 | 
				
			||||||
 | 
					|   2    |
 | 
				
			||||||
 | 
					|   3    |
 | 
				
			||||||
 | 
					|   7    |
 | 
				
			||||||
 | 
					|   8    |
 | 
				
			||||||
 | 
					|   10   |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					CREATE TABLE SQL_10
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					     log_id  int
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					INSERT INTO SQL_10 (log_id) VALUES (1), (2), (3), (7), (8), (10);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 问题
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					编写SQL 查询得到 Logs 表中的连续区间的开始数字和结束数字。按照 start_id 排序。查询结果格式如下:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| start_id | end_id |
 | 
				
			||||||
 | 
					| -------- | ------ |
 | 
				
			||||||
 | 
					| 1        | 3      |
 | 
				
			||||||
 | 
					| 7        | 8      |
 | 
				
			||||||
 | 
					| 10       | 10     |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 解答
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sql
 | 
				
			||||||
 | 
					-- 方法一
 | 
				
			||||||
 | 
					with t1 as (
 | 
				
			||||||
 | 
					    select *, log_id - row_number() over (order by log_id) as gr from SQL_10
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select min(log_id) as start_id, max(log_id) as end_id from t1 group by gr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- 方法二
 | 
				
			||||||
 | 
					with t1 as (
 | 
				
			||||||
 | 
					    select *, log_id - row_number() over (order by log_id) as gr, log_id - lag(log_id,1) over () as diff from SQL_10
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					t2 as (
 | 
				
			||||||
 | 
					    select log_id, gr from t1 where ifnull(diff,-1) <> 1
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					t3 as (
 | 
				
			||||||
 | 
					    select *, log_id - row_number() over (order by log_id) as gr, log_id - lead(log_id,1) over () as diff from SQL_10
 | 
				
			||||||
 | 
					),
 | 
				
			||||||
 | 
					t4 as (
 | 
				
			||||||
 | 
					 select log_id, gr from t3 where ifnull(diff, 1) <> -1
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					select t2.log_id as start_id, t4.log_id as end_id from t2, t4 where t2.gr = t4.gr;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 技巧
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如何求连续区间?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1)行号过滤法
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      通过row_number() 生成连续行号,与区间列进行差值运算,得到的临时结果如果相同表示为同一连续区间
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2) 错位比较法
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      通过row_number() / row_number()  + 1 分别生成原生的和错位的连续行号列,进行连表操作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      也可以通过lag/lead函数直接生成错位列
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
 
 | 
					 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Centos 安装 Docker
 | 
					# Linux 安装 Docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,6 +18,39 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## oracle linxu 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. 执行以下命令,以安装Docker依赖项:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					sudo yum -y install yum-utils device-mapper-persistent-data lvm2
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. 执行以下命令,以添加Docker官方GPG key:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. 执行以下命令,以安装Docker CE:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					sudo yum install docker-ce
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. 启动并设置Docker服务为开机自启:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					sudo systemctl start docker
 | 
				
			||||||
 | 
					sudo systemctl enable docker
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					通过`docker --version`命令,您可以检查Docker是否已经安装。如果命令输出了版本信息,说明已经成功安装Docker CE。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					希望这次能给您提供一个更简洁的方法。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 启动服务
 | 
					## 启动服务
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
@@ -64,14 +97,17 @@ Docker中国:https://registry.docker-cn.com
 | 
				
			|||||||
### 写入配置文件 重启服务
 | 
					### 写入配置文件 重启服务
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
   sudo mkdir -p /etc/docker
 | 
					sudo mkdir -p /etc/docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sudo tee /etc/docker/daemon.json <<-'EOF'
 | 
					#注意EOF前不能有空格    
 | 
				
			||||||
    {
 | 
					sudo tee /etc/docker/daemon.json <<-'EOF'
 | 
				
			||||||
      "registry-mirrors": ["https://mirror.ccs.tencentyun.com"]
 | 
					{
 | 
				
			||||||
    }
 | 
					"registry-mirrors": ["https://mirror.ccs.tencentyun.com"]
 | 
				
			||||||
    EOF
 | 
					}
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
    sudo systemctl daemon-reload
 | 
					    sudo systemctl daemon-reload
 | 
				
			||||||
    sudo systemctl restart docker
 | 
					    sudo systemctl restart docker
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,6 @@ s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可
 | 
				
			|||||||
可以使用正则  特殊字符\转义 
 | 
					可以使用正则  特殊字符\转义 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sed ”s/要被取代的字串/新的字串/g“ fileName
 | 
					sed "s/要被取代的字串/新的字串/g" fileName
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -637,7 +637,15 @@ psql -Uicctestedb -dicctestedb -h192.168.53.123 -f ~/
 | 
				
			|||||||
# -O 不设置表归属,
 | 
					# -O 不设置表归属,
 | 
				
			||||||
# -F c 自定义压缩
 | 
					# -F c 自定义压缩
 | 
				
			||||||
# -v 显示详情
 | 
					# -v 显示详情
 | 
				
			||||||
./pg_dump -Uenterprisedb -diccedb -h192.168.53.118 -O -v -F c -f ~/diccedb_202207_29.data.sql
 | 
					./pg_dump -Uenterprisedb -diccedb -h192.168.53.118 -O -v -F c -f ~/alg.da
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 数据导入
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#导入数据
 | 
					#导入数据
 | 
				
			||||||
#-c 指定恢复过程中清空目标数据库中的现有表
 | 
					#-c 指定恢复过程中清空目标数据库中的现有表
 | 
				
			||||||
@@ -655,10 +663,6 @@ psql -Uicctestedb -dicctestedb -h192.168.53.123 -f ~/
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### COPY 导出导出部分数据
 | 
					#### COPY 导出导出部分数据
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```sh
 | 
					```sh
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										214
									
								
								redis/redis-3.0.3,哨兵集群.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								redis/redis-3.0.3,哨兵集群.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,214 @@
 | 
				
			|||||||
 | 
					## redis-v3.0.3哨兵集群搭建文档
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 准备工作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 主机
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					准备三台全新 centos linux 服务器 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					固定IP 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					192.168.1.11 
 | 
				
			||||||
 | 
					192.168.1.12
 | 
				
			||||||
 | 
					192.168.1.13
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**以下命令如无特殊说明 在三台主机中均要执行**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					准备环境 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					yum install make gcc wget
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					创建用户 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					useradd  redis
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					创建相关目录
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					mkdir -p /opt/{app/redis,applog}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					授权
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					chown -R redis:redis /opt/app/redis/
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					chown -R redis:redis /opt/applog/redis/
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 编译源码
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					切换用户
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					su - redis
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					下载源码
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cd /opt/app/redis/
 | 
				
			||||||
 | 
					wget https://download.redis.io/releases/redis-3.0.3.tar.gz
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					解压源码
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					tar -zxvf redis-3.0.3.tar.gz
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					编译源码 这里为了和生产一致 使用libc 内存分配器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cd redis-3.0.3
 | 
				
			||||||
 | 
					make MALLOC=libc
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					安装
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					make PREFIX=/opt/app/redis/ install
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					配置 path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					echo 'export PATH=$PATH:/opt/app/redis/bin' >> ~/.bashrc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source ~/.bashrc
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 配置redis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					复制配置文件
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cp /opt/app/redis/redis-3.0.3/src/redis.conf /opt/app/redis/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cp /opt/app/redis/redis-3.0.3/src/sentinel.conf /opt/app/redis/
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					编辑配置文件 redis.conf 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					sed -i 's/daemonize no/daemonize yes/g' redis.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sed -i 's|^logfile ""$|logfile "/opt/applog/redis/redis.log"|g' redis.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sed -i 's|^dir "./"$|dir "/opt/app/redis/"|g' redis.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sed -i 's/appendonly no/appendonly yes/g' redis.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sed -i 's/^# cluster-node-timeout 15000$/cluster-node-timeout 5000/g' redis.conf
 | 
				
			||||||
 | 
					#设置主从复制密码
 | 
				
			||||||
 | 
					sed -i 's/^# masterauth <master-password>$/masterauth dUw~7a)6/g' redis.conf
 | 
				
			||||||
 | 
					#设置 节点密码
 | 
				
			||||||
 | 
					sed -i 's/^# requirepass foobared$/requirepass dUw~7a)6/g' redis.conf
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					配置主从节点
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在 192.168.1.12,192.168.1.13 两台机子中执行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					echo "slaveof 10.23.101.3 6379" >> redis.conf
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					编辑配置文件 sentinel.conf 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					sed -i 's|^\(sentinel monitor mymaster\) 127.0.0.1|\1 181.168.1.11|' sentinel.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#设置哨兵密码
 | 
				
			||||||
 | 
					sed -i 's/^#sentinel auth-pass <master-name> <password>/sentinel auth-pass mymaster HmpYZ2KB/g' sentinel.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "daemonize yes" >> sentinel.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					编写动脚本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					echo "bin/redis-server redis.config">/opt/app/redis/start.sh
 | 
				
			||||||
 | 
					chmod 775 start.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "bin/redis-sentinel sentinel.config">/opt/app/redis/start-sentinel.sh
 | 
				
			||||||
 | 
					chmod 775 start.sh
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					指定用户启动
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					su -s /bin/bash -c "$(pwd)/bin/redis-sentinel $(pwd)/sentinel.conf " redis
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 启动
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					先启动三个redis节点
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					bash start.sh
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					再启动 sentinel j节点
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					bash start-sentinel.sh
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 验证
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					登录三个redis节点 分别写入key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					192.168.1.11  成功写入  并同步至 192.168.1.12,192.168.1.13
 | 
				
			||||||
 | 
					192.168.1.12	写入失败
 | 
				
			||||||
 | 
					192.168.1.13	写入失败
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					登录哨兵节点 查看哨兵信息
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					redis-cli  -p 26379
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sentinel sentinels mymaster
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					杀死 主节点
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					分别查看 另外两台redis 的info 信息 是否发生切换
 | 
				
			||||||
		Reference in New Issue
	
	Block a user