SQL1 查找最晚入职员工的所有信息
查找employees里最晚入职员工的所有信息
SELECT * FROM employees WHERE hire_date = (SELECT MAX(hire_date) FROM employees);
SQL2 查找入职员工时间排名倒数第三的员工所有信息
请你查找employees里入职员工时间排名倒数第三的员工所有信息
①考虑去重:
select * from employees where hire_date=( select distinct hire_date from employees order by hire_date DESC limit 2,1);
②默认用美式排名(即用同名次的情况时,后续的名次会跳过),所以不加 DISTINCT 去重
法2. 计数法:
思路:"第N高" → "比它高的值的个数 + 1 = N"
SELECT * FROM employees a WHERE ( SELECT COUNT(*) + 1 FROM employees WHERE hire_date > a.hire_date ) = 3;
SQL3 查找各个部门当前领导当前薪水详情以及其对应部门编号
查找各个部门当前领导薪水详情以及其对应部门编号dept_no,输出结果以salaries.emp_no升序排序
SELECT s.*, d.dept_no FROM salaries s JOIN dept_manager d USING(emp_no) WHERE s.to_date='9999-01-01' AND d.to_date='9999-01-01' ORDER BY s.emp_no;
注意:找的是当前领导,即在职的领导,所以要加上连接条件 s.to_date = '9999-01-01' AND d.to_date = '9999-01-01' (当然也可以写在 WHERE 里作为连接后的筛选条件,但从性能上讲写在 ON 里好一点)
SQL4 查找所有已经分配部门的员工的last_name和first_name
查找所有已经分配部门的员工的last_name和first_name以及dept_no,未分配的部门的员工不显示
SELECT last_name, first_name, dept_no FROM employees INNER JOIN dept_emp USING(emp_no);
SQL5 查找所有员工的last_name和first_name以及对应部门编号dept_no
请你查找所有已经分配部门的员工的last_name和first_name以及dept_no,也包括暂时没有分配具体部门的员工
SELECT last_name, first_name, d.dept_no FROM employees e LEFT JOIN dept_emp d USING(emp_no);
SQL7 查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t
思路:"超过15次" :很明显是要按员工分组统计并用 HAVING 进行分组后筛选
SELECT emp_no, COUNT(*) t FROM salaries GROUP BY emp_no HAVING COUNT(*) > 15; -- MySQL 里的话可以直接用列别名 t > 15
SQL8 找出所有员工当前具体的薪水salary情况
请你找出所有员工当前((to_date=‘9999-01-01’))的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示
SELECT DISTINCT salary FROM salaries WHERE to_date = '9999-01-01' ORDER BY salary DESC;
SQL10 获取所有非manager的员工emp_no
有两种方法:
法1. LEFT JOIN + IS NULL
SELECT e.emp_no FROM employees e LEFT JOIN dept_manager d USING(emp_no) WHERE d.dept_no IS NULL;
法2. 子查询 + NOT IN
SELECT emp_no FROM employees WHERE emp_no NOT IN( SELECT emp_no FROM dept_manager );
SQL11 获取所有员工当前的manager
获取所有的当前员工和员工对应的经理,如果员工本身是经理的话则不显示
SELECT d.emp_no, dm.emp_no AS manager FROM dept_emp d JOIN dept_manager dm USING(dept_no) WHERE d.emp_no!=dm.emp_no AND e.to_date='9999-01-01'AND dm.to_date='9999-01-01' -- 不等于符号 <> 或 !=
☆☆SQL12 获取所有部门中当前员工薪水最高的相关信息
获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary,按照部门编号升序排列
法1. 子查询
SELECT dept_no, d1.emp_no, salary AS maxSalary FROM dept_emp d1 JOIN salaries s1 USING(emp_no) WHERE d1.to_date='9999-01-01'AND s1.to_date='9999-01-01'AND salary in( SELECT MAX(salary) FROM salaries s2 JOIN dept_emp d2 USING(emp_no) WHERE d1.dept_no=d2.dept_no AND d2.to_date='9999-01-01'AND s2.to_date='9999-01-01' ) ORDER BY d1.dept_no;
法2. 用窗口函数里的排序函数
待学
补充:如果这题不需要给出emp_no(即只求所有部门中当前员工薪水最高值),则用INNER JOIN和GROUP BY和MAX即可解决:
SELECT dept_no, d.emp_no, MAX(salary) AS maxSalary FROM dept_emp d JOIN salaries s USING(emp_no) WHERE d.to_date='9999-01-01'AND s.to_date='9999-01-01' GROUP BY dept_no ORDER BY dept_no;
SQL15 查找employees表所有emp_no为奇数
查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列
SELECT * FROM employees WHERE emp_no % 2 = 1 -- 也可写作 emp_no MOD 2 = 1 AND last_name != 'Mary' ORDER BY hire_date DESC;
SQL16 统计出当前各个title类型对应的员工当前薪水对应的平均工资
统计出当前各个title类型对应的员工薪水对应的平均工资avg。结果给出title以及平均工资avg,并且以avg升序排序
SELECT title, AVG(s.salary) FROM titles t INNER JOIN salaries s ON t.emp_no = s.emp_no AND t.to_date = '9999-01-01' AND s.to_date = '9999-01-01' GROUP BY title ORDER BY AVG(s.salary);
☆SQL17 获取当前薪水第二多的员工的emp_no以及其对应的薪水salary
思路:类似第2题,属于第 N 值问题里的一般情况,可以用排序提取法、计数法或用窗口函数中的排序函数解决
排序提取法:薪水第2高的员工 → 薪水等于第2高的薪水的员工
SELECT emp_no, salary FROM salaries WHERE salary = ( SELECT salary FROM salaries ORDER BY salary DESC LIMIT 1, 1 );
计数法:薪水第2高 → 薪水比他高的只有1人
SELECT emp_no, salary FROM salaries s WHERE ( SELECT COUNT(*) FROM salaries WHERE salary > s.salary ) = 1;
max()+子查询
select emp_no, salary from salaries where salary=( select max(salary) from salaries where salary <>( select max(salary) from salaries ));
用窗口函数中的排序函数
SELECT emp_no, salary FROM ( SELECT emp_no, salary, RANK() OVER(ORDER BY salary DESC) rk FROM salaries ) WHERE rk = 2;
☆SQL18 查找当前薪水排名第二多的员工编号emp_no
查找当前薪水排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不能使用order by完成
计数法:
SELECT e.emp_no, s.salary, e.last_name, e.first_name FROM salaries s INNER JOIN employees e ON s.emp_no = e.emp_no AND s.to_date = '9999-01-01' WHERE ( SELECT COUNT(*) FROM salaries WHERE to_date = '9999-01-01' AND salary > s.salary ) = 1;
max()+子查询
select s.emp_no, s.salary, e.last_name, e.first_name from salaries s join employees e on s.emp_no = e.emp_no where s.salary = -- 第三步: 将第二高工资作为查询条件 ( select max(salary) -- 第二步: 查出除了原表最高工资以外的最高工资(第二高工资) from salaries where salary < ( select max(salary) -- 第一步: 查出原表最高工资 from salaries where to_date = '9999-01-01' ) and to_date = '9999-01-01' ) and s.to_date = '9999-01-01'
SQL19 查找所有员工的last_name和first_name以及对应的dept_name
查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
SELECT last_name, first_name, dept_name FROM employees LEFT JOIN dept_emp USING(emp_no) LEFT JOIN departments USING(dept_no);
☆QL21 查找所有员工自入职以来的薪水涨幅情况
查找所有员工自入职以来的薪水涨幅情况,给出员工编号emp_no以及其对应的薪水涨幅growth,并按照growth进行升序(离职的员工 salaries 表的最新的 to_date != '9999-01-01',这样的数据不显示在查找结果里面)
思路:工资涨幅 = 目前工资 - 入职时工资,所以要将 employees 表两次连接 salaries 表,第一次连接是为了获取入职时的工资(s.from_date = e.hire_date),第二次连接是为了获取目前的工资(to_date = ‘9999-01-01’)
SELECT e.emp_no, s2.salary - s1.salary growth FROM employees e INNER JOIN salaries s1 ON s1.emp_no = e.emp_no AND s1.from_date = e.hire_date -- 获取该员工入职时的工资 INNER JOIN salaries s2 ON s2.emp_no = e.emp_no AND s2.to_date = '9999-01-01' -- 获取该员工目前的工资 -- 同时也将筛选掉离职的员工:因为离职员工没有 to_date = '9999-01-01' 的记录,但内连接只保留有匹配记录的员工 ORDER BY growth;
SQL22 统计各个部门的工资记录数
统计各个部门的工资记录数,给出部门编码dept_no、部门名称dept_name以及部门在salaries表里面有多少条记录sum,按照dept_no升序排序
SELECT d.dept_no, d.dept_name, count(d.dept_no) FROM departments d JOIN dept_emp de USING(dept_no) LEFT JOIN salaries s USING(emp_no) GROUP BY d.dept_no ORDER BY d.dept_no
☆SQL23 对所有员工的当前薪水按照salary进行按照1-N的排名
对所有员工当前的薪水按照salary进行按照1-N的排名,相同salary并列且按照emp_no升序排列
法1:窗口函数
SELECT emp_no, salary, DENSE_RANK() OVER(ORDER BY salary DESC) AS t_rank FROM salaries ORDER BY t_rank,emp_no;
法2:子查询计数法
名次 = 比他高的个数 + 1
求 "比他高的个数" 时要注意两点:
- 要考虑到 NULL 值的情况(除非明确知道没有 NULL 值)
- 这里是中式排名求 "档次",所以要加 DISTINCT 去重
SELECT emp_no, salary, (SELECT COUNT(DISTINCT salary) + 1 FROM salaries WHERE salary > s.salary OR salary IS NULL AND s.salary IS NOT NULL ) t_rank FROM salaries s WHERE to_date = '9999-01-01' ORDER BY t_rank, emp_no;
SQL24 获取所有非manager员工当前的薪水情况
法1:首选连接法
SELECT de.dept_no, de.emp_no, s.salary FROM dept_emp de JOIN dept_manager dm ON dm.dept_no = de.dept_no AND de.to_date = '9999-01-01' AND dm.to_date = '9999-01-01' AND de.emp_no <> dm.emp_no -- 非 manager JOIN salaries s ON de.emp_no = s.emp_no AND s.to_date = '9999-01-01';
法2:子查询
SELECT de.dept_no, a.emp_no, s.salary FROM (SELECT e.emp_no FROM employees e LEFT JOIN dept_manager dm USING(emp_no) WHERE dept_no IS NULL) a JOIN salaries s ON s.emp_no=a.emp_no JOIN dept_emp de on de.emp_no = a.emp_no where s.to_date='9999-01-01';
SQL25 获取员工其当前的薪水比其manager当前薪水还高的相关信息
获取员工其当前的薪水比其manager当前薪水还高的相关信息, 第一列给出员工的emp_no, 第二列给出其manager的manager_no, 第三列给出该员工当前的薪水emp_salary, 第四列给该员工对应的manager当前的薪水manager_salary
思路:能用连接法首选连接法,这道题明显是可以的
先用 dept_emp 连接 dept_manager,再 两次 连接 salaries 表分别获取员工和经理的工资
注意在连接条件里筛选 "当前"(to_date = ‘9999-01-01’)和 "员工比经理薪水高"(s1.salary > s2.salary)的记录
选取需要的列即可
SELECT de.emp_no, dm.emp_no manager_no, s1.salary emp_salary, s2.salary manager_salary FROM dept_emp de JOIN dept_manager dm ON de.dept_no = dm.dept_no AND de.to_date = '9999-01-01' AND dm.to_date = '9999-01-01' -- "当前" JOIN salaries s1 ON de.emp_no = s1.emp_no AND s1.to_date = '9999-01-01' JOIN salaries s2 ON dm.emp_no = s2.emp_no AND s2.to_date = '9999-01-01' AND s1.salary > s2.salary; -- 员工比经理薪水高
SQL26 汇总各个部门当前员工的title类型的分配数目
汇总各个部门当前员工的title类型的分配数目,即结果给出部门编号dept_no、dept_name、其部门下所有的员工的title以及该类型title对应的数目count,结果按照dept_no升序排序
SELECT d.dept_no, d.dept_name, t.title, COUNT(t.title) FROM departments d JOIN dept_emp de ON d.dept_no = de.dept_no AND de.to_date = '9999-01-01' JOIN titles t ON de.emp_no = t.emp_no AND t.to_date = '9999-01-01' GROUP BY d.dept_no, d.dept_name, t.title ORDER BY dept_no;