目录
- 11. 获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date='9999-01-01'。
- 12. 获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary
- 13. 从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t
- 14. 从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。
- 15. 查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列
- 16. 统计出当前各个title类型对应的员工当前薪水对应的平均工资。结果给出title以及平均工资avg。
- 17. 获取当前(to_date='9999-01-01')薪水第二多的员工的emp_no以及其对应的薪水salary
- 18. 查找当前薪水(to_date='9999-01-01')排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不准使用order by
- 19. 查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
- 20. 查找员工编号emp_no为10001其自入职以来的薪水salary涨幅值growth
- 完整的个人练习代码
11. 获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date='9999-01-01'。
结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no
-- dept_emp部门员工表找到员工emp_no对应的部门dept_no, dept_manager部门管理表再找到管理者emp_no
SELECT de.emp_no, dm.emp_no AS manager_no
FROM dept_emp AS de, dept_manager AS dm
WHERE de.emp_no!=dm.emp_no AND dm.dept_no=de.dept_no
AND de.to_date="9999-01-01" AND dm.to_date="9999-01-01";
运行时间:30ms
占用内存:3464k
-- 使用内连接INNER JOIN关联部门员工表和管理员表
SELECT de.emp_no, dm.emp_no AS manager_no
FROM dept_emp AS de
INNER JOIN dept_manager AS dm
ON dm.dept_no=de.dept_no
WHERE de.emp_no!=dm.emp_no
AND de.to_date="9999-01-01" AND dm.to_date="9999-01-01";
运行时间:16ms
占用内存:3344k
12. 获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary
当前(to_date="9999-01-01")各部门薪水最高员工
注意:该题目和审核系统是有坑的...
SELECT re1.dept_no, re2.emp_no, re1.salary
FROM (
-- 先找出各部门最高薪水值 通过部门编号分组
SELECT dept_em.dept_no, MAX(em_sa.salary) AS salary
FROM (
SELECT emp_no, salary
FROM salaries
WHERE to_date = '9999-01-01'
) AS em_sa
LEFT JOIN (
SELECT emp_no, dept_no
FROM dept_emp
WHERE to_date = '9999-01-01'
) AS dept_em
ON em_sa.emp_no = dept_em.emp_no
GROUP BY dept_no) re1
JOIN (
-- 再找出各部门员工的薪水值 通过左连接
SELECT dept_em.dept_no, em_sa.emp_no, em_sa.salary AS salary
FROM (
SELECT emp_no, salary
FROM salaries
WHERE to_date = '9999-01-01'
) AS em_sa
LEFT JOIN (
SELECT emp_no, dept_no
FROM dept_emp
WHERE to_date = '9999-01-01'
) AS dept_em
ON em_sa.emp_no = dept_em.emp_no) re2
-- 通过连接获得最高薪水值对应的员工编号
ON re1.dept_no = re2.dept_no AND re1.salary = re2.salary
ORDER BY re1.dept_no;
运行时间:20ms
占用内存:5076k
- 分析SQL代码:
第一种解法: 6.67's
-- 通过to_date缩减需要选取的数据
-- 当前salaries表的emp_no和salary
SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01';
-- 当前dept_emp表的dept_no和emp_no
SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01';
-- 通过部门编号分组, 当前各部门的最高薪水salary和部门编号dept_no
SELECT dm.dept_no, MAX(se.salary) salary
FROM (
(
SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01'
) AS se
LEFT JOIN
(
SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01'
) AS dm
ON se.emp_no=dm.emp_no)
GROUP BY dm.dept_no;
-- 无需分组, 将部门/员工/薪水合并到一个表内
SELECT dm.dept_no, dm.emp_no, se.salary
FROM (
(
SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01'
) AS se
LEFT JOIN
(
SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01'
) AS dm
ON se.emp_no=dm.emp_no);
-- 通过`部门/最高薪水`的条件 去筛选/定位 `员工编号`
SELECT re1.dept_no, re2.emp_no, re1.salary
FROM (
SELECT dm.dept_no, MAX(se.salary) salary
FROM (
(
SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01'
) AS se
LEFT JOIN
(
SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01'
) AS dm
ON se.emp_no=dm.emp_no)
GROUP BY dm.dept_no
) AS re1 JOIN (
SELECT dm.dept_no, dm.emp_no, se.salary
FROM (
(
SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01'
) AS se
LEFT JOIN
(
SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01'
) AS dm
ON se.emp_no=dm.emp_no)
) AS re2
ON re2.dept_no=re1.dept_no AND re2.salary=re1.salary
ORDER BY re1.dept_no;
第二种解法: 5.93's 结果是一样的,但无法通过牛客的审核
SELECT de.dept_no,sa.emp_no,re.sal AS salary
FROM (
-- 通过分组,拿到各部门编号以及对应的最高薪水
SELECT d.dept_no, MAX(s.salary) AS sal
FROM dept_emp AS d JOIN salaries AS s
ON d.emp_no=s.emp_no AND d.to_date='9999-01-01' AND s.to_date='9999-01-01'
GROUP BY d.dept_no
) AS re, dept_emp AS de, salaries AS sa
-- 三表查询 re的最高薪水 部门员工表的部门编号 薪水表的员工编号
WHERE re.dept_no=de.dept_no AND de.emp_no=sa.emp_no AND re.sal=sa.salary;
13. 从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t
SELECT title, COUNT(title) AS t FROM titles GROUP BY title HAVING t >= 2;
运行时间:18ms
占用内存:3424k
- 注意:where和having的不同之处在于,where是查找之前的限定,而having是查找之后
14. 从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。
注意对于重复的emp_no进行忽略
-- 统计拥有相同 title 的不同员工的个数 distinct可以放入函数体内
SELECT title, COUNT(DISTINCT emp_no) AS t FROM titles GROUP BY title HAVING t >= 2;
运行时间:17ms
占用内存:3300k
15. 查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列
-- 判断属性奇偶数 1)取余 2)除与2再乘与2 3)位运算
SELECT * FROM employees WHERE emp_no%2=1 AND last_name!='Mary' ORDER BY hire_date DESC;
运行时间:20ms
占用内存:3400k
mysql判断奇数偶数,并思考效率
16. 统计出当前各个title类型对应的员工当前薪水对应的平均工资。结果给出title以及平均工资avg。
-- 注意avg是sql语法的关键字,需要``对其进行标注
SELECT t.title, AVG(s.salary) AS `avg` FROM titles AS t INNER JOIN salaries AS s ON s.emp_no=t.emp_no AND s.to_date='9999-01-01' AND t.to_date='9999-01-01' GROUP BY title;
运行时间:28ms
占用内存:3404k
17. 获取当前(to_date='9999-01-01')薪水第二多的员工的emp_no以及其对应的薪水salary
-- 将salaries表按薪水salary逆序排列,再选取第二位
SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01' ORDER BY salary DESC LIMIT 1,1;
运行时间:22ms
占用内存:3320k
-- 以上方法是有缺陷的,题意是指薪水第二多,而同一薪水可能有多名员工
-- 先求出当前第二多薪水数额(distinct和group by都可以)
SELECT DISTINCT salary FROM salaries WHERE to_date='9999-01-01' ORDER BY salary DESC LIMIT 1,1;
SELECT salary FROM salaries WHERE to_date='9999-01-01' GROUP BY salary ORDER BY salary DESC LIMIT 1,1;
-- 再通过当前时间和薪水数额定位员工编号
SELECT emp_no, salary FROM salaries WHERE salary = (
SELECT DISTINCT salary FROM salaries WHERE to_date='9999-01-01' ORDER BY salary DESC LIMIT 1,1
) AND to_date='9999-01-01';
运行时间:22ms
占用内存:3552k
18. 查找当前薪水(to_date='9999-01-01')排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不准使用order by
-- 先找出当前最多薪水数额
SELECT MAX(salary) FROM salaries WHERE to_date='9999-01-01';
-- 使用排除法,在去掉最大值的序列中,此时最大值就原序列的第二大值
SELECT MAX(salary) FROM salaries
WHERE to_date='9999-01-01' AND salary NOT IN (
SELECT MAX(salary) FROM salaries WHERE to_date='9999-01-01'
);
-- 使用以上求取得到的第二大值
SELECT s.emp_no, s.salary, e.last_name, e.first_name
FROM salaries AS s INNER JOIN employees AS e ON s.emp_no=e.emp_no
WHERE s.to_date='9999-01-01'
AND s.salary = (
SELECT MAX(salary) FROM salaries
WHERE to_date='9999-01-01' AND salary NOT IN (
SELECT MAX(salary) FROM salaries WHERE to_date='9999-01-01'
)
);
运行时间:24ms
占用内存:3304k
19. 查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
-- 先将员工表employees和部门员工表dept_emp连接 合成部门员工详细表ds
SELECT e.emp_no, de.dept_no FROM employees AS e LEFT JOIN dept_emp AS de ON e.emp_no=de.emp_no;
-- 再将部门信息表department和部门员工详细表ds连接
SELECT ds.last_name, ds.first_name, d.dept_name FROM (
SELECT e.last_name, e.first_name, de.dept_no FROM employees AS e LEFT JOIN dept_emp AS de ON e.emp_no=de.emp_no
) AS ds LEFT JOIN departments AS d ON d.dept_no=ds.dept_no;
运行时间:18ms
占用内存:3312k
-- 第一次 left join 是把未分配部门的员工算进去了,但是只得到了部门编号dept_no,没有部门名dept_name,
-- 所以第二次也要 left join 把含有部门名 departments表 连接起来,
-- 否则在第二次连接时就选不上未分配部门的员工了
SELECT e.last_name, e.first_name, d.dept_name
FROM employees AS e
LEFT JOIN dept_emp AS de ON e.emp_no = de.emp_no
LEFT JOIN departments AS d ON de.dept_no = d.dept_no;
运行时间:20ms
占用内存:3404k
20. 查找员工编号emp_no为10001其自入职以来的薪水salary涨幅值growth
个人理解为:获得入职时的工资距离最新的工资的涨幅情况
-- 最大值-最小值 这种解法是有问题的 其是以薪水一直在涨/上升的前提下
SELECT (MAX(salary)-MIN(salary)) AS growth FROM salaries WHERE emp_no='10001';
运行时间:19ms
占用内存:3424k
-- 薪水salary涨幅值growth 当前薪水-入职薪水
SELECT (ma.salary-mi.salary) AS growth
FROM (
-- 入职薪水
SELECT salary FROM salaries WHERE emp_no='10001' ORDER BY to_date LIMIT 0,1
) AS mi, (
-- 当前薪水
SELECT salary FROM salaries WHERE emp_no='10001' ORDER BY to_date DESC LIMIT 0,1
) AS ma;
运行时间:21ms
占用内存:3688k
完整的个人练习代码
我的练习SQL代码已经上传至Github:https://github.com/slowbirdoflsh/newcode-sql-practice
仅供参考~~~