diff --git "a/41 \345\221\250\344\272\232\350\276\211/20231018 \346\225\260\346\215\256\345\272\223\345\244\215\344\271\240.md" "b/41 \345\221\250\344\272\232\350\276\211/20231018 \346\225\260\346\215\256\345\272\223\345\244\215\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..c7255e38fec1837942c13ae7e63b9ab2ac1c1b13 --- /dev/null +++ "b/41 \345\221\250\344\272\232\350\276\211/20231018 \346\225\260\346\215\256\345\272\223\345\244\215\344\271\240.md" @@ -0,0 +1,301 @@ +``` +-- 比例函数 返回<= 或 >= 当前行的所有数占总行数的比率 +cume_dist() over(order by 字段 desc) -- 大于 +-- 分组函数 +ntile(组的数量) over(partition by 分组字段 order by 分组依据) + +-- 前后函数 +lag(字段,n) over(partition by 分组字段 order by 排序字段) -- 前n行 +lead(字段,n) over(partition by 分组字段 order by 排序字段) -- 后n行 +-- 窗口大小 +函数() over(partition by 字段 rows between 起始行 and 结束行) + -- rows 启用窗口大小 + -- between ... and ... 范围区间 + -- unbounded preceding 起始行 + -- n preceding 前n行 + -- current row 当前行 + -- n following 后n行 + -- unbounded following 最终行 + +-- 指定差 +timestampdiff(返回日期类型,日期1,日期2); -- 后面的日期减前面的日期 + -- 返回日期类型:year:年,month:月,day:日 +``` + +# 作业 + +``` +CREATE DATABASE a CHARSET utf8; +use a; +create table if not exists `employee` +( + `eid` int not null auto_increment comment '员工id' primary key, + `ename` varchar(20) not null comment '员工名称', + `dname` varchar(50) not null comment '部门名称', + `hiredate` datetime not null comment '入职日期', + `birth` date not null comment '生日', + `salary` double null comment '基本薪资', + `start_sal` double null comment '入职薪资' +); + +insert into `employee` (`ename`, `dname`, `hiredate`,`birth`, `salary`,`start_sal`) values ('傅嘉熙', '开发部', '2002-08-20 12:00:04','1980-12-10', 9000,6500); +insert into `employee` (`ename`, `dname`, `hiredate`, `birth`,`salary`,`start_sal`) values ('武晟睿', '开发部', '2002-06-12 13:54:12', '1984-2-5',9500,6000); +insert into `employee` (`ename`, `dname`, `hiredate`, `birth`,`salary`,`start_sal`) values ('孙弘文', '开发部', '2003-10-16 08:27:06','1979-8-7', 9400,8000); +insert into `employee` (`ename`, `dname`, `hiredate`,`birth`, `salary`,`start_sal`) values ('潘乐驹', '开发部', '2004-04-22 03:56:11','1980-5-12', 9500,6800); +insert into `employee` (`ename`, `dname`, `hiredate`,`birth`, `salary`,`start_sal`) values ('潘昊焱', '人事部', '2007-02-24 03:40:02','1987-2-12', 5000,4500); +insert into `employee` (`ename`, `dname`, `hiredate`,`birth`, `salary`,`start_sal`) values ('沈涛', '人事部', '2012-12-14 09:16:37','1993-4-30', 6000,5500); +insert into `employee` (`ename`, `dname`, `hiredate`, `birth`,`salary`,`start_sal`) values ('江峻熙', '人事部', '2018-05-12 01:17:48','1990-6-8', 5000,3000); +insert into `employee` (`ename`, `dname`, `hiredate`,`birth`, `salary`,`start_sal`) values ('陆远航', '人事部', '2018-04-14 03:35:57','1989-11-13', 5500,5000); +insert into `employee` (`ename`, `dname`, `hiredate`, `birth`,`salary`,`start_sal`) values ('姜煜祺', '销售部', '2020-03-23 03:21:05','1995-1-1', 6000,5500); +insert into `employee` (`ename`, `dname`, `hiredate`, `birth`,`salary`,`start_sal`) values ('邹明', '销售部', '2015-11-23 23:10:06','1996-2-19', 6800,6000); +insert into `employee` (`ename`, `dname`, `hiredate`, `birth`,`salary`,`start_sal`) values ('董擎苍', '销售部', '2012-02-12 07:54:32','1985-10-7', 6500,4800); +insert into `employee` (`ename`, `dname`, `hiredate`,`birth`, `salary`,`start_sal`) values ('钟俊驰', '销售部', '2010-04-10 12:17:06','1981-3-25', 6000,3500); + +-- 员工按工龄,每年增加50元薪水。实发薪资 = 基本薪资 + 工龄 * 50 + +### -- 窗口函数 + + + +#求每个部门的员工总数 +select DISTINCT dname, +count(dname) over(partition by dname) 'count' +from employee; + +#求每个部门的平均工资 +select DISTINCT dname, +AVG(salary) over(partition by dname) '平均工资' +from employee; + +#求每个部门的工资排名(从高到低,相同工资并列,并执行跳过排序) + +SELECT dname, ename, salary, + RANK() OVER (PARTITION BY dname ORDER BY salary DESC) +FROM employee; +#求公司所有员工的年龄排序(相同年龄并列,执行跳过排序) +WITH a as +(SELECT DISTINCT + dname, + ename, + birth, +FLOOR(DATEDIFF(NOW(),birth)/365) 年龄 +FROM + employee) + SELECT *,RANK() over (PARTITION BY dname ORDER BY 年龄 ) from a; +#求每个部门的员工工龄排序(相同年龄并列,执行顺序排序) +select DISTINCT ename, + hiredate,RANK() over( ORDER BY hiredate ) +from employee; +#计算每个员工的工资与该部门平均工资的差额 + + +select DISTINCT ename,dname, +AVG(salary) over(ORDER BY dname ) 平均工资, +salary-AVG(salary) over(ORDER BY dname ) 差额 +from employee; + + + +#按员工工资进行排序,比较相邻两个员工的工资,输出比较高的工资 +-- SELECT ename, salary, +-- LEAD(salary) OVER (ORDER BY salary) AS higher_salary +-- FROM employee; + +SELECT *, +ROW_NUMBER() over (ORDER BY salary), + max(salary) OVER (rows BETWEEN current row and 1 following) AS higher_salary + FROM employee; + + +#按员工工资进行排序,查询当前员工与前一位和后一位的工资平均值 + +SELECT *, +ROUND(AVG(salary) over (rows BETWEEN 1 preceding AND 1 following),2) +FROM employee; +#按员工工资进行排序,查询当前员工至最后一位员工的工资总和 +SELECT *, + SUM(salary) OVER (ORDER BY salary DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS 工资总和 +FROM employee; + +#计算每个部门内最高薪资与平均薪资的差额 +SELECT DISTINCT dname,MAX(salary) OVER (PARTITION BY dname), AVG(salary) OVER (PARTITION BY dname),MAX(salary) OVER (PARTITION BY dname) - AVG(salary) OVER (PARTITION BY dname) AS 差额 +FROM employee; + +#找出各部门年薪第二高的员工 + +SELECT dname, ename, salary*12 年薪 +FROM ( + SELECT dname, ename, salary, DENSE_RANK() OVER (PARTITION BY dname ORDER BY salary DESC) AS salary_rank + FROM employee +) sub +WHERE salary_rank = 2; + +with a as ( SELECT dname, ename, salary, DENSE_RANK() OVER (PARTITION BY dname ORDER BY salary DESC) AS salary_rank + FROM employee) + SELECT dname, ename, salary*12 年薪 FROM a WHERE a.salary_rank = 2; + +#查询各部门中小于等于当前员工实际薪资的比例 + SELECT *, CUME_DIST() OVER(PARTITION BY dname ORDER BY salary desc) 比例 FROM employee; + + + +#查询每个员工工资在全部员工中的排名比例 +SELECT ename, salary, + ROUND( CUME_DIST() OVER(ORDER BY salary),2) AS 排名比例 +FROM employee; + + +#查询每个部门工资排名在前25%的员工记录数 +-- SELECT * from +-- (SELECT *, NTILE(4) OVER(PARTITION BY dname ORDER BY salary DESC) pm FROM employee ) a WHERE pm =1; +-- +WITH b as( +SELECT *, ROUND( CUME_DIST() OVER(PARTITION by dname ORDER BY salary desc),2) a +from employee) +SELECT * from b where a<=0.25; + +#每个部门按年龄进行排序,求当前员工与前一位员工的年龄差 +-- SELECT dname, ename, birth, +-- DATEDIFF(birth,LAG(birth) OVER (PARTITION BY dname ORDER BY birth) ) AS 与前一位员工的年龄差 +-- FROM employee +-- ORDER BY dname; + +SELECT dname, ename, DATEDIFF(now(),birth)/365, + ROW_NUMBER() OVER (PARTITION BY dname ORDER BY DATEDIFF(now(),birth)/365) + ,lag( DATEDIFF(now(),birth)/365,1) over (PARTITION BY dname ORDER BY DATEDIFF(now(),birth)/365) + AS 与前一位员工的年龄差 +FROM employee; +#按入职日期进行排序,查询公司每个员工与后面一个员工的入职天数差异 +SELECT dname, ename, hiredate,LEAD(hiredate,1) OVER ( ORDER BY hiredate)后一位员工的, + DATEDIFF(LEAD(hiredate,1) OVER ( ORDER BY hiredate),hiredate) AS 与后一位员工的年龄差 +FROM employee; + +#将每个部门的员工按工资平均分为2个组,组1为低工资,组2为高工资 +-- SELECT +-- *, +-- CASE +-- WHEN ROW_NUMBER() OVER (PARTITION BY dname ORDER BY salary) <= COUNT(*) OVER (PARTITION BY dname) / 2 THEN '低工资' +-- ELSE '高工资' +-- END AS salary_group +-- FROM +-- employee; +-- -- +-- SELECT dname, ename,CASE WHEN b.a=1 then '低工资' ELSE '高工资' END 组 +-- from +-- (SELECT dname, ename, NTILE(2) OVER (PARTITION BY dname ORDER BY salary) a +-- FROM employee) b ; + +-- +SELECT + dname, + ename, + salary, +CASE + NTILE( 2 ) OVER ( PARTITION BY dname ORDER BY salary ) + WHEN 1 THEN + '低工资' ELSE '高工资' + END 组 +FROM + employee; + +#将所有员工按照工龄分为4个组,并统计每个组的人数 +WITH a as( +SELECT ename,hiredate, NTILE(4) OVER (ORDER BY hiredate) b +FROM employee) +SELECT *,count(ename) over(partition by b) from a; + + +#将员工按照工资分为3个组,并统计组别,每组平均工资,工资范围(first_value、last_value) +-- SELECT +-- group_number, +-- AVG(salary) AS average_salary, +-- FIRST_VALUE(salary) OVER (PARTITION BY group_number ORDER BY salary) AS range_start, +-- LAST_VALUE(salary) OVER (PARTITION BY group_number ORDER BY salary) AS range_end +-- FROM ( +-- SELECT +-- *, +-- NTILE(3) OVER (ORDER BY salary) AS group_number +-- FROM employee +-- ) AS grouped_employee +-- GROUP BY group_number; +-- +WITH a as( + SELECT + *, + NTILE(3) OVER (ORDER BY salary) AS 组别 + FROM employee) +SELECT *,avg(salary) over(PARTITION by 组别) , +CONCAT(FIRST_VALUE(salary)over(PARTITION by 组别),'-', +LAST_VALUE(salary)over(PARTITION by 组别)) +from a; + + +### -- 非窗口函数 + +#按照工龄区分等级,小于5年为新员工,5-15年为老员工,大于15年为骨灰级员工,输出姓名,部门,工龄,级别 +SELECT + ename, + dname, + hiredate, + FLOOR(DATEDIFF(CURDATE(), hiredate) / 365) , + CASE + WHEN FLOOR(DATEDIFF(CURDATE(), hiredate) / 365)<5 THEN '新员工' + WHEN FLOOR(DATEDIFF(CURDATE(), hiredate) / 365)<=15 THEN '老员工' + ELSE '骨灰级员工' + END AS actual_age +FROM employee; + + + + +#返回员工的实际年龄,如果小于当前日期则减1岁 + +SELECT + ename, + dname, + birth, + FLOOR(DATEDIFF(NOW(), birth) / 365) +FROM employee; + + +#求每个员工还有多少天过生日,并返回下次生日是星期几 + +-- SELECT +-- ename, +-- birth, +-- case +-- when +-- DATE_FORMAT(NOW(),'%m-%d')