【SOL练习】——公司人事数据仓库建表练习,附详细思路解析,冲,冲,冲

公司人事数据仓库建表练习


🧡💛💚💙💜🤎💗🧡💛💚💙💜🤎💗
感谢各位一直以来的支持和鼓励制作不易
🙏 求点赞 👍 ➕ 收藏 ⭐ ➕ 关注
一键三连走起 ! ! !
🧡💛💚💙💜🤎💗 🧡💛💚💙💜🤎💗


创建表1:公司员工表(emp)

字段:工号,姓名,工作岗位,部门经理,受雇日期,薪金,奖金,部门编号

DROP TABLE IF EXISTS  `emp`;
CREATE TABLE `emp` (
  `EMPNO` int(4) NOT NULL,
  `ENAME` varchar(10) DEFAULT NULL,
  `JOB` varchar(9) DEFAULT NULL,
  `MGR` varchar(10) DEFAULT NULL,
  `HIREDATE` date DEFAULT NULL,
  `SAL` int(7) DEFAULT NULL,
  `COMM` int(7) DEFAULT NULL,
  `DEPTNO` int(2) DEFAULT NULL,
  PRIMARY KEY (`EMPNO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

向emp表中插入相关数据

insert into `emp`(`EMPNO`,`ENAME`,`JOB`,`MGR`,`HIREDATE`,`SAL`,`COMM`,`DEPTNO`) values
('7369','SMITH','CLERK','7902','1980-12-17','800',null,'20'),
('7499','ALLEN','SALESMAN','7698','1981-02-20','1600','300','30'),
('7521','WARD','SALESMAN','7698','1981-02-22','1250','500','30'),
('7566','JONES','MANAGER','7839','1981-04-02','2975',null,'20'),
('7654','MARTIN','SALESMAN','7698','1981-09-28','1250','1400','30'),
('7698','BLAKE','MANAGER','7839','1981-05-01','2850',null,'30'),
('7782','CLARK','MANAGER','7839','1981-06-09','2450',null,'10'),
('7788','SCOTT','ANALYST','7566','1987-04-19','3000',null,'20'),
('7839','KING','PRESIDENT',null,'1981-11-17','5000',null,'10'),
('7844','TURNER','SALESMAN','7698','1981-09-08','1500','0','30'),
('7876','ADAMS','CLERK','7788','1987-05-23','1100',null,'20'),
('7900','JAMES','CLERK','7698','1981-12-03','950',null,'30'),
('7902','FORD','ANALYST','7566','1981-12-03','3000',null,'20'),
('7934','MILLER','CLERK','7782','1982-01-23','1300',null,'10');

创建表2:公司部门表(dept)

字段:部门编号,部门名称,部门所在地

DROP TABLE IF EXISTS  `dept`;
CREATE TABLE `dept` (
  `DEPTNO` int(2) NOT NULL,
  `DNAME` varchar(14) DEFAULT NULL,
  `LOC` varchar(13) DEFAULT NULL,
  PRIMARY KEY (`DEPTNO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

向dept表添加相关数据

insert into `dept`(`DEPTNO`,`DNAME`,`LOC`) values
('10','ACCOUNTING','NEW YORK'),
('20','RESEARCH','DALLAS'),
('30','SALES','CHICAGO'),
('40','OPERATIONS','BOSTON');


查看表1数据emp

在这里插入图片描述

查看表2数据dept

在这里插入图片描述

练习题

1. 列出至少有4个员工的所有部门的部门编号和名称。

-- 解题思路1:
-- step1:
-- 根据emp表员工的部门号deptno分组,求出每个部门的员工人数count(*),再根据条件“至少有4个员工” count(*)>=4 来筛选,并得到部门号deptno
SELECT COUNT(*) AS c,deptno FROM emp GROUP BY deptno HAVING c>=4;
--  step2:
--  dept连接step1查询到的表,来筛选获取部门名称dname,deptno
SELECT dname,dept.deptno FROM dept
LEFT JOIN
(SELECT COUNT(*) AS c,deptno FROM emp GROUP BY deptno HAVING c>=4) AS s
ON s.deptno=dept.deptno
WHERE s.deptno=dept.deptno;

--  解题思路2:使用in(set)来获取符合条件的deptno
SELECT dept.dname,dept.deptno FROM dept
WHERE deptno in (
SELECT deptno FROM
(SELECT COUNT(*) AS c,deptno FROM emp GROUP BY deptno HAVING c>=4) AS s
);

查询结果

在这里插入图片描述

2. 列出薪金比“SMITH”多的所有员工的信息

-- 解法1;采用子查询做筛选条件
SELECT * FROM emp
WHERE SAL>(SELECT SAL FROM emp WHERE ENAME='SMITH' ) ORDER BY SAL;

-- 解法2:采用连表查询
SELECT e1.* FROM 
emp AS e1
LEFT JOIN emp AS e2
ON e1.ename=e2.ename
WHERE e1.sal >(SELECT sal FROM emp WHERE ename='SMITH')  ORDER BY sal;

查询结果
在这里插入图片描述

3. 列出所有员工的姓名及其直接上级的姓名。

-- 解法1:使用连表查询,连接条件e1.mgr=e2.empno
SELECT e1.ENAME AS '员工姓名',e2.ENAME AS '直接上级'
FROM emp AS e1
LEFT JOIN emp AS e2
ON e1.MGR=e2.EMPNO;

在这里插入图片描述
验证结果:
在这里插入图片描述

4. 列出受雇日期早于其直接上级的所有员工

--  解题思路1:根据e1.MGR=e2.EMPNO连接,再使用不能式比较日期
-- 	注意:使用不等式比较日期,要保证两个日期的类型格式完全相同,否则异常
--  例如:1.“2021-08-05”和“2021-6-1”,会报错
-- 				2.“2021-08-11”和“2021年08月13号”,会报错
SELECT e1.* FROM
emp AS e1 
LEFT JOIN
emp AS e2
ON e1.MGR=e2.EMPNO
WHERE e1.HIREDATE<e2.HIREDATE;

        对于解题思路1,我们可以将日期的数据格式不一致使用类型转换函数convert() 将日期数据格式转换为一致,然后再比较,但是这样我们要写的sql语句就会很繁杂, 这样,我们不如可以直接使用datediff()函数来比较没看解题思路2,sql会很简洁

--  解题思路2:
-- 通过日期加减的结果正负判断大小
-- 根据datediff(e1.HIREDATE,e2.HIREDATE)<0
-- 或datediff(e2.HIREDATE,e1.HIREDATE)>0  来筛选
SELECT e1.* FROM
emp AS e1 
LEFT JOIN
emp AS e2
ON e1.MGR=e2.EMPNO
WHERE DATEDIFF(e1.HIREDATE,e2.HIREDATE)<0;

        所以一般最好还是使用解题思路2来比较日期,会更可取些
在这里插入图片描述
验证结果
在这里插入图片描述

5. 列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门,并根据部门名称分组,员工编号排序,显示出每个部门每个员工的所有信息

– 解题思路1:
– step1:以dept表为基准连接emp表,筛选出所有信息
– step2:先分组,将每个部门的员工信息放在一块而,但是对dname部门名称分组,只显示第一条数据,其它员工数据就没有显示,解决这种问题可以对员工编号一起分组,(每个员工的empno是唯一的且只有一个,这样就显示出了所有员工的信息了)
– step3: 排序,若直接对员工编号排序(在整张表所有部门中排序),会打乱之前分组的结构,那么我们可以先对部门号排序,再对员工编号排序(此时的排序就是在部门里面进行排序),则不会打乱分组结果,

SELECT dept.DNAME,emp.*
FROM dept
LEFT JOIN emp
ON emp.DEPTNO=dept.DEPTNO 
GROUP BY dept.DNAME,emp.EMPNO 
ORDER BY dept.DEPTNO, emp.EMPNO ;

在这里插入图片描述

6. 列出所有“CLERK”(办事员)的姓名及其部门名称


--  解题思路1:使用左外连接
SELECT emp.ENAME,dept.DNAME FROM emp
LEFT JOIN dept
ON emp.DEPTNO=dept.DEPTNO
WHERE emp.JOB='CLERK';

-- 解题思路2:使用内连接(求两张表的交集)
SELECT ENAME,DNAME FROM dept
INNER JOIN 
(SELECT * FROM emp WHERE JOB='CLERK') AS s
ON dept.DEPTNO=s.deptno;

在这里插入图片描述

7. 列出最低薪金大于1500的各种工作

-- 解题思路1:使用聚集函数min()求最低薪金,要先对job分好组
SELECT JOB,MIN(SAL) AS minsal FROM emp
GROUP BY JOB
HAVING  minsal>1500;

在这里插入图片描述

8. 列出在部门“SALES”(销售部)工作的员工的姓名,假定不知道销售部的部门编号

-- 解题思路1:子查询 先获得部门的编号,再去emp表筛选员工
SELECT deptno FROM dept WHERE DNAME ='SALES'; -- 获取部门号

SELECT ENAME FROM emp
WHERE DEPTNO =(SELECT deptno FROM dept WHERE DNAME ='SALES');

-- 解题思路2: 连表联查(外连接)
SELECT ENAME FROM emp
LEFT JOIN dept
ON emp.DEPTNO=dept.DEPTNO
WHERE DNAME='SALES';
-- 内连接
SELECT ENAME FROM emp
INNER JOIN dept
ON emp.DEPTNO=dept.DEPTNO
WHERE DNAME='SALES';

在这里插入图片描述

9. 列出薪金高于公司平均薪金的所有员工

--  解题思路1: 先求出公司平均薪金
SELECT AVG(sal) AS '平均薪金'  FROM emp;
-- 使用子查询
SELECT * FROM emp
HAVING SAL>(SELECT AVG(sal) AS '平均薪金'  FROM emp);

在这里插入图片描述

10.列出与“SCOTT”从事相同工作的所有员工

SELECT * FROM emp
WHERE JOB=(SELECT JOB FROM emp WHERE ENAME='SCOTT') 
AND ENAME<>'SCOTT';

在这里插入图片描述

11.列出薪金等于部门30中员工的薪金的所有员工的姓名和薪金

--   解题思路1:先求出部门30的员工的工资
SELECT SAL FROM emp WHERE DEPTNO=30;
--  再筛选所有员工中薪金和部门30中相同的员工的信息,去掉部门30自己的员工
SELECT * FROM emp
WHERE SAL in (SELECT SAL FROM emp WHERE DEPTNO=30)
AND DEPTNO<>30;

在这里插入图片描述

12.列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金

--   解题思路1:先求出部门30的员工的工资中工资最高的
SELECT MAX(SAL) FROM emp WHERE DEPTNO=30;
--  再筛选所有员工中薪金高于部门30中最高薪金的员工的信息
SELECT ENAME,SAL FROM emp
WHERE SAL > (SELECT MAX(SAL) FROM emp WHERE DEPTNO=30);

在这里插入图片描述

13.列出在每个部门工作的员工数量、平均工资和平均服务期限

--  求员工数量 count(*)
-- 奖金comm中有空值,需要替换为0来计算,null不能计算,否则结果全为0
SELECT  CASE WHEN COMM IS NULL THEN 0 ELSE COMM END AS COMM FROM  emp;
-- 求平均工资AVG(薪金+奖金)
SELECT AVG( SAL +(CASE WHEN COMM IS NULL THEN 0 ELSE COMM END)) FROM emp;
-- 求平均服务期限AVG(DATEDIFF(CURRENT_DATE,hiredate))
SELECT AVG( DATEDIFF(CURRENT_DATE,HIREDATE)) FROM emp;

SELECT dept.DEPTNO,DNAME,
count(*) AS '部门员工数量',
AVG( SAL +(CASE WHEN COMM IS NULL THEN 0 ELSE COMM END)) AS '平均工资',
AVG( DATEDIFF(CURRENT_DATE,HIREDATE)) AS '平均服务期限'
FROM emp
LEFT JOIN dept
ON emp.DEPTNO=dept.DEPTNO
GROUP BY DEPTNO;

在这里插入图片描述

14.列出所有员工的姓名、部门名称和工资

SELECT ENAME,DNAME,
(SAL+case WHEN COMM IS NULL THEN 0 ELSE COMM END) AS '工资'
FROM emp INNER JOIN dept ON emp.DEPTNO=dept.DEPTNO;

在这里插入图片描述

15.列出所有部门的详细信息和部门人数

-- 解题思路
-- 1:先对emp表中部门号分组,再求分组中的人数
SELECT count(*) AS '部门人数',DEPTNO FROM emp GROUP BY DEPTNO;
-- 2.连表查询,取出结果

SELECT dept.*,s.`部门人数`  FROM dept
LEFT JOIN 
(SELECT count(*) AS '部门人数',DEPTNO FROM emp GROUP BY DEPTNO) AS s
ON s.DEPTNO=dept.DEPTNO;

在这里插入图片描述

16.列出各种工作的最低工资

SELECT JOB,
MIN(SAL+case WHEN COMM IS null THEN 0 ELSE COMM END ) AS '最低工资'
FROM emp GROUP BY JOB ;

在这里插入图片描述

17.列出各个部门的MANAGER(经理)的最低薪金

SELECT MIN(SAL) FROM emp WHERE JOB='MANAGER' GROUP BY DEPTNO; 

在这里插入图片描述

18.列出所有员工的年工资,按年薪从低到高排序

SELECT emp.*,
12*(SAL+ CASE WHEN COMM IS NULL THEN 0 ELSE COMM END) AS NSAL
FROM emp ORDER BY NSAL;

在这里插入图片描述

19. 列出每个部门薪金前两名最高的人员名称以及薪金

-- 解题思路:先用子查询对同个部门中的员工根据薪金比较,并记录每个员工的比较次数
-- 子查询:
-- SELECT COUNT(*) FROM emp AS emp2 WHERE emp1.DEPTNO=emp2.deptno AND emp1.SAL<emp2.sal)
-- where筛选条件:
-- 条件1:emp1.DEPTNO=emp2.deptno 实现对emp表中的员工按部门编号分组,
--        也就是查询对同个部门中的员工
-- 条件2:emp1.SAL<emp2.sal实现对emp表中同部门的员工薪金进行比较,
-- 然后select count(*) 得到的就是同时满足where条件1和2的员工比较次数也就是同部门不同员工之间薪金比较)
-- 满足条件的,count(*)就记录一次,满足条件1前提,记录的满足条件2的员工的比较次数(也就是记录比ep1.sal大的员工的数目)
-- 数目越少那么对应着其sal就越大,反之越小;这样数目county(*)为0的就是sal最大的,为1的其次

-- 为什么条件2中使用'<' 而不用 '>' ,因为若用“>”,count(*)得到的就是比最大的sal小的sal的数量
-- 那么当我们处理大量数据的时候就不知道,这个数量具体是多少,那么在写外层的where时就不知到给多大的数了,
-- 像此题使用“<”就可以用where 2>(),确定得到的就是top2第一大的和第二大的,反之就不确定了

SELECT emp1.ENAME,emp1.SAL FROM  emp AS emp1
WHERE  2>
(SELECT COUNT(*) FROM emp AS emp2 
WHERE emp1.DEPTNO=emp2.deptno AND emp1.SAL<emp2.sal)
ORDER BY DEPTNO;

在这里插入图片描述

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北慕辰

你的鼓励是小北最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值