2、[编程题]查找入职员工时间排名倒数第三的员工所有信息
数据库表:
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
题解:
select * from employees where hire_date=(select distinct hire_date from employees order by hire_date desc limit 2,1);
语法注释:
distinct :用来过滤重复数据
distinct支持单列、多列的去重方式。
单列去重的方式简明易懂,即相同值只保留1个。
多列的去重则是根据指定的去重的列信息来进行,即只有所有指定的列信息都相同,才会被认为是重复的信息。
详细用法可参考:https://blog.youkuaiyun.com/ljl890705/article/details/70602442
order by:如果我们需要对读取的数据进行排序,我们就可以使用 MySQL 的 ORDER BY 子句来设定你想按哪个字段哪种方式来进行排序,再返回搜索结果。
以下是 SQL SELECT 语句使用 ORDER BY 子句将查询数据排序后再返回数据:
SELECT field1, field2,...fieldN table_name1, table_name2...
ORDER BY field1, [field2...] [ASC [DESC]]
- 你可以使用任何字段来作为排序的条件,从而返回排序后的查询结果。
- 你可以设定多个字段来排序。
- 你可以使用 ASC 或 DESC 关键字来设置查询结果是按升序或降序排列。 默认情况下,它是按升序排列。
- 你可以添加 WHERE...LIKE 子句来设置条件。
limit:
SELECT
*
FROM
表名 limit m,n;
1.m代表从m+1条记录行开始检索,n代表取出n条数据。(m可设为0)
如:SELECT * FROM 表名 limit 6,5;
表示:从第7条记录行开始算,取出5条数据
2.值得注意的是,n可以被设置为-1,当n为-1时,表示从m+1行开始检索,直到取出最后一条数据。
如:SELECT * FROM 表名 limit 6,-1;
表示:取出第6条记录行以后的所有数据。
3.若只给出m,则表示从第1条记录行开始算一共取出m条
如:SELECT * FROM 表名 limit 6;
表示:取出前6条记录行。
3、查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_no
数据库表:
CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
输出描述:
解法一:
SELECT s.*, d.dept_no FROM salaries s , dept_manager d
WHERE s.to_date='9999-01-01'
AND d.to_date='9999-01-01'
AND s.emp_no = d.emp_no;
解法二:
SELECT s.*, d.dept_no FROM salaries s INNER JOIN dept_manager d
ON s.to_date='9999-01-01'
AND d.to_date='9999-01-01'
AND s.emp_no = d.emp_no;
语法注释:
首先说一下注意事项:
这里的坑主要在于两个表的逻辑关系,题目要求是薪水情况以及部门编号,再结合输出情况dept_no 被放到了最后一列,可见是主表是“salaries”。这里顺序错了就会提示:您的代码无法通过所有用例。
如下面缩写即提示错误:
select d.emp_no,s.* from dept_manager d,salaries s
where d.emp_no=s.emp_no and d.to_date='9999-01-01' and s.to_date='9999-01-01';
其次:
直接写s.to_date=d.to_date='9999-01-01',也是不通过的,需要严格按照上面语法将日期分别写出来,具体原因是什么待解决??????
最后介绍解法二中的连接多表的语法;
使用 MySQL 的 JOIN 在两个或多个表中查询数据。
JOIN 按照功能大致分为如下三类:
- INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录。
- LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录。
- RIGHT JOIN(右连接): 与 LEFT JOIN 相反,用于获取右表所有记录,即使左表没有对应匹配的记录。
具体可参考:http://www.runoob.com/mysql/mysql-join.html
4、查找所有已经分配部门的员工的last_name和first_name
数据库表:
CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
输出描述:
题解:
SELECT e.last_name , e.first_name ,d.dept_no
FROM employees e INNER JOIN dept_emp d
ON e.emp_no = d.emp_no;
语法注释:
参考上一题即可,inner join表示两表中相同的字段;
5、查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工
数据库表:
CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
题解:
SELECT e.last_name , e.first_name ,d.dept_no
FROM employees e LEFT JOIN dept_emp d
ON d.emp_no=e.emp_no;
语法注释:
根据题目,需要找出employes表中所有信息,同时找出dept_emp表中的部分信息的dept_no,即便该表中有的字段无对应信息;
因此需要使用LEFT JOIN提取信息:
LEFT JOIN 会读取左边数据表的全部数据,即便右边表无对应数据
6、查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序
数据库表:
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
SELECT s.emp_no ,s.salary
FROM salaries s INNER JOIN employees e
ON e.emp_no = s.emp_no AND e.hire_date = s.from_date
ORDER BY e.emp_no desc;
语法注释:
此题应注意以下四个知识点:
1、由于测试数据中,salaries.emp_no不唯一(因为号码为emp_no的员工会有多次涨薪的可能,所以在salaries中对应的记录不止一条),employees.emp_no唯一,即salaries的数据会多于employees,因此需先找到employees.emp_no在salaries表中对应的记录salaries.emp_no,则有限制条件e.emp_no = s.emp_no
2、根据题意注意到salaries.from_date 和employees.hire_date的值应该要相等,因此有限制条件 e.hire_date = s.from_date
3、根据题意要按照emp_no值逆序排列,因此最后要加上 ORDER BY e.emp_no DESC
4、为了代码良好的可读性,运用了Alias别名语句,将employees简化为e,salaries简化为s,即 employees AS e与salaries AS s,其中AS可以省略
7、查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t
数据库表:
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
SELECT emp_no , COUNT(emp_no) AS t FROM salaries GROUP BY emp_no HAVING t>15;
语法注释:
GROUP BY:根据一个或多个列对结果集进行分组。在分组的列上我们可以使用 function如:COUNT, SUM, AVG,等函数。
由于COUNT()函数不可用于WHERE语句中,故使用HAVING语句来限定t>15的条件
WHERE 与 HAVING的区别:
WHERE语句在GROUP BY语句之前;SQL会在分组之前计算WHERE语句。
HAVING语句在GROUP BY语句之后;SQL会在分组之后计算HAVING语句。
8、找出所有员工当前(to_date='9999-01-01')具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示
数据库表:
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
SELECT salary FROM salaries WHERE to_date= '9999-01-01'
GROUP BY salary
ORDER BY salary desc;
语法注释:
使用GROUP BY解决了salary的重复问题;
去重语法distinct和group by的区别:https://www.jianshu.com/p/34800d06f63d
这里一般建议选择GROUP BY
各类使用方法可参考:https://www.cnblogs.com/vanl/p/5912903.html
9、获取所有部门当前manager的当前薪水情况,给出dept_no, emp_no以及salary,当前表示to_date='9999-01-01'
数据库表:
CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
SELECT d.dept_no , d.emp_no , s.salary
FROM dept_manager d INNER JOIN salaries s
WHERE d.to_date='9999-01-01' AND s.to_date = '9999-01-01' AND d.emp_no = s.emp_no;
语法注释:
10、获取所有非manager的员工emp_no
数据库表:
CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
题解:
方法一:使用NOT IN选出在employees但不在dept_manager中的emp_no记录
1 2 |
|
方法二:先使用LEFT JOIN连接两张表,再从此表中选出dept_no值为NULL对应的emp_no记录
1 2 3 |
|
方法三:方法二的简版,使用单层SELECT语句即可
1 2 3 |
|
语法注释:
在牛客网的讨论中,出现了下面一种错误解法,有大神做了详细的错误解析:
select A.emp_no from employees A,dept_manager B where A.emp_no not in B.emp_no;
解析:
作者:wasrehpic
链接:https://www.nowcoder.com/questionTerminal/32c53d06443346f4a2f2ca733c19660c
来源:牛客网
本身存在语法错误,in关键字后要跟一组数据,而不是一个,要将B.emp_no用括号括起来才能正常运行;其次(B.emp_no)中没用到SELECT,所以(B.emp_no)只包含dept_manager表中第一条记录的emp_no,即10002,而不是包含了所有记录的emp_no。因此以上语句将会输出除10002外的所有emp_no。
11、获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date='9999-01-01'。结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no。
数据库表:
CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
题解:
SELECT de.emp_no, dm.emp_no AS manager_no
FROM dept_emp AS de INNER JOIN dept_manager AS dm
ON de.dept_no = dm.dept_no
WHERE dm.to_date = '9999-01-01' AND de.to_date = '9999-01-01' AND de.emp_no != dm.emp_no;
语法注释:
!=和 <>:两者在MySQL中都是不等于的意思;
本题应注意以下三点:
1、用 INNER JOIN 连接两张表,因为要输出自己的经理,得知自己与经理的部门要相同,故有限制条件 de.dept_no = dm.dept_no;部门一定有manager,员工不一定有manager,所以不用de.dept_no = dm.dept_no ;
2、再用 WHERE 限制当前员工与当前经理的条件,即 dm.to_date 等于 '9999-01-01' 、de.to_date 等于 '9999-01-01' 、 de.emp_no 不等于 dm.emp_no;
3、为了增强代码可读性,将 dept_emp 用别名 de 代替,dept_manager 用 dm 代替,最后根据题意将 de.emp_no 用别名 manager_no 代替后输出;
12、获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary
数据库表:
CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
方法一:
SELECT d.dept_no ,d.emp_no, s.salary
FROM salaries s INNER JOIN dept_emp d
ON d.emp_no = s.emp_no
WHERE d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'
GROUP BY d.dept_no HAVING max(s.salary);
方法二:
SELECT d.dept_no, s.emp_no, MAX(s.salary) AS salary
FROM salaries s INNER JOIN dept_emp d
ON d.emp_no = s.emp_no
WHERE d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'
GROUP BY d.dept_no;
语法注释:
此题的难点是在,如何将dept_no分组找出它对应的最高salary;
我们使用GROUP BY d.dept_no 将dept_no进行分组;同时需注意方法一中max(s.salary)要在GROUP BY 之后,如果放在前面的话排序的就不是我们的目标dept_no了而是整体的表;
方法二是采用的一个大神思路:
链接:https://www.nowcoder.com/questionTerminal/4a052e3e1df5435880d4353eb18a91c6
来源:牛客网
此题思路如下:
1、先用INNER JOIN连接两张表,限制条件是两张表的emp_no相同,即d.emp_no = s.emp_no;
2、选取每个员工当前的工资水平,用d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'作条件限制,因为此表中每条最新记录的 to_date 都用 9999-01-01 表示;
3、用GROUP BY d.dept_no将每个部门分为一组,用MAX()函数选取每组中工资最高者;
4、将salaries用s代替,dept_emp用d代替,最后将MAX(s.salary)用salary代替后输出。
13、从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。
数据库表:
CREATE TABLE IF NOT EXISTS "titles" (
`emp_no` int(11) NOT NULL,
`title` varchar(50) NOT NULL,
`from_date` date NOT NULL,
`to_date` date DEFAULT NULL);
题解:
SELECT title, COUNT(title) AS t FROM titles GROUP BY title HAVING t >= 2;
语法注释:
此题应注意以下三点:
1、用COUNT()函数和GROUP BY语句可以统计同一title值的记录条数
2、根据题意,输出每个title的个数为t,故用AS语句将COUNT(title)的值转换为t
3、由于WHERE后不可跟COUNT()函数,故用HAVING语句来限定t>=2的条件;
14、从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。注意对于重复的emp_no进行忽略。
数据库表:
CREATE TABLE IF NOT EXISTS "titles" (
`emp_no` int(11) NOT NULL,
`title` varchar(50) NOT NULL,
`from_date` date NOT NULL,
`to_date` date DEFAULT NULL);
题解:
SELECT title, COUNT(DISTINCT emp_no) AS t FROM titles GROUP BY title HAVING t >= 2;
语法注释:
此题应注意以下三点:
1、先用GROUP BY title将表格以title分组,再用COUNT(DISTINCT emp_no)可以统计同一title值且不包含重复emp_no值的记录条数
2、根据题意,输出每个title的个数为t,故用AS语句将COUNT(DISTINCT emp_no)的值转换为t
3、由于WHERE后不可跟COUNT()函数,故用HAVING语句来限定t>=2的条件
15、查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列
数据库表:
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
题解:
方法一:直接计算
SELECT * FROM employees WHERE emp_no %2=1 AND last_name != 'Mary' ORDER BY hire_date desc;
方法二:按位与
SELECT * FROM employees WHERE emp_no &1 AND last_name != 'Mary' ORDER BY hire_date desc;
语法注释:
参考文章:https://blog.youkuaiyun.com/zhazhagu/article/details/80452473
方法一:直接计算法,如果查找偶数则是,%2=0
方法二:按位与查找法
查询奇数的方法 &1:1的二进制是0001,与运算符:1 & 1 = 1, 1 & 0 = 0, 0 & 1 = 0, 0 & 0 = 0;所以可以保证最后一位是奇数。
查询偶数的方法 字段=(字段>>1)<<1:这是左移和右移运算符,先整除再乘,意思就是先整除2再乘以2,看前后结果是否一样,一样的就是偶数。
方法三:函数法--MOD(x,y) ,返回 x 除以 y 以后的余数。但是本方法是可行的,不过是在牛客网测试未通过。
SELECT * FROM employees WHERE MOD(emp_no, 2)=1 AND last_name != 'Mary' ORDER BY hire_date desc;
方法四:正则表达式
SELECT * FROM employees WHERE emp_no REGEXP '[13579]$' AND last_name != 'Mary' ORDER BY hire_date desc;
[13579]:奇数字符集合。匹配所包含的任意一个字符。
aa$ :以aa结尾;
参考:http://www.runoob.com/mysql/mysql-regexp.html
本方法适用于查询身份证末尾有X,但是仍然需要查询出奇偶数的情况。
16、统计出当前各个title类型对应的员工当前薪水对应的平均工资。结果给出title以及平均工资avg。
数据库表:
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
CREATE TABLE IF NOT EXISTS "titles" (
`emp_no` int(11) NOT NULL,
`title` varchar(50) NOT NULL,
`from_date` date NOT NULL,
`to_date` date DEFAULT NULL);
题解:
SELECT t.title ,AVG(s.salary)
FROM salaries s iINNER JOIN titles t
ON s.emp_no = t.emp_no
AND s.to_date = '9999-01-01' AND t.to_date ='9999-01-01'
GROUP BY t.title;
语法注释:
此题的思路如下:
1、先用INNER JOIN连接两张表,限制条件是两张表的emp_no相同,即s.emp_no = t.emp_no;
2、选取员工当前日期薪水对应的平均工资,所以根据之前的题目,默认当前日期是:s.to_date = '9999-01-01' AND t.to_date = '9999-01-01'作条件限制,因为此表中每条最新记录的 to_date 都用 9999-01-01 表示;
3、用GROUP BY t.title将title进行分组;
4、将salaries用s代替,titles用t代替;
5、计算平均薪资用AVG函数,AVG(s.salary);
17、获取当前(to_date='9999-01-01')薪水第二多的员工的emp_no以及其对应的薪水salary
数据库表:
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
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) ;
语法注释:
此题的思路如下:
1、当前日期是to_date = '9999-01-01'
2、员工的薪水第二多,需要先对薪水排序,降序排列OEDER BY salary desc,再找出排名第二的薪水LIMIT 1,1;
LIMIT m,n : 表示从第m+1条开始,取n条数据;
LIMIT n : 表示从第0条开始,取n条数据,是limit(0,n)的缩写。
3、考虑到薪水排名第一的员工可能有多个,使用DISTINCT去除重复数据;
关于LIMIT的详细用法可参考:https://www.jb51.net/article/125394.htm
18、查找当前薪水(to_date='9999-01-01')排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不准使用order by
数据库表:
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
SELECT e.emp_no, MAX(s.salary) AS salary, e.last_name, e.first_name
FROM employees AS e INNER JOIN salaries AS s
ON e.emp_no = s.emp_no
WHERE s.to_date = '9999-01-01'
AND s.salary NOT IN (SELECT MAX(salary) FROM salaries WHERE to_date = '9999-01-01');
语法注释:
本题做法很多,主要思想为多层SELECT嵌套与MAX()函数结合
1、先利用MAX()函数找出salaries中当前薪水最高者,即SELECT MAX(salary) FROM salaries WHERE to_date = '9999-01-01'
2、再利用INNER JOIN连接employees与salaries表,限定条件为【同一员工】e.emp_no = s.emp_no、【当前】s.to_date = '9999-01-01'与【非薪水最高】s.salary NOT IN (SELECT MAX(salary) FROM salaries WHERE to_date = '9999-01-01')
3、在以上限制条件下找薪水最高者,即为所有员工薪水的次高者
19、查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
数据库表:
CREATE TABLE `departments` (
`dept_no` char(4) NOT NULL,
`dept_name` varchar(40) NOT NULL,
PRIMARY KEY (`dept_no`));
CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
题解:
SELECT em.last_name, em.first_name, dp.dept_name
FROM (employees AS em LEFT JOIN dept_emp AS de ON em.emp_no = de.emp_no)
LEFT JOIN departments AS dp ON de.dept_no = dp.dept_no;
语法注释:
本题思路为运用两次LEFT JOIN连接嵌套
1、第一次LEFT JOIN连接employees表与dept_emp表,得到所有员工的last_name和first_name以及对应的dept_no,也包括暂时没有分配部门的员工
2、第二次LEFT JOIN连接上表与departments表,即连接dept_no与dept_name,得到所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
20、查找员工编号emp_no为10001其自入职以来的薪水salary涨幅值growth
数据库表:
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
SELECT (
(SELECT salary FROM salaries WHERE emp_no = 10001 ORDER BY to_date DESC LIMIT 1) -
(SELECT salary FROM salaries WHERE emp_no = 10001 ORDER BY to_date ASC LIMIT 1)
) AS growth;
语法注释:
本题严谨的思路如下:
1、先分别找到emp_no=10001的员工的第一次工资记录与最后一次工资记录
2、再将最后一次工资记录减去第一次工资记录得到入职以来salary的涨幅,最后用别名growth代替
21、查找所有员工自入职以来的薪水涨幅情况,给出员工编号emp_no以及其对应的薪水涨幅growth,并按照growth进行升序
数据库表:
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
方法一:内层用LEFT JOIN,外层用INNER JOIN(内层也可以改用 INNER JOIN)
1 2 3 4 5 |
|
方法二:内外层都用FROM并列查询
1 2 3 4 5 |
|
方法三:
|
语法注释:
方法一、二解题思路:
本题思路是先分别用两次LEFT JOIN左连接employees与salaries,建立两张表,分别存放员工当前工资(sCurrent)与员工入职时的工资(sStart),再用INNER JOIN连接sCurrent与sStart,最后限定在同一员工下用当前工资减去入职工资。
22、统计各个部门对应员工涨幅的次数总和,给出部门编码dept_no、部门名称dept_name以及次数sum
数据库表:
CREATE TABLE `departments` (
`dept_no` char(4) NOT NULL,
`dept_name` varchar(40) NOT NULL,
PRIMARY KEY (`dept_no`));
CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
SELECT de.dept_no, dp.dept_name, COUNT(s.salary) AS sum
FROM (dept_emp AS de INNER JOIN salaries AS s ON de.emp_no = s.emp_no)
INNER JOIN departments AS dp ON de.dept_no = dp.dept_no
GROUP BY de.dept_no;
语法注释:
本题关键是要将 每个部门分组,并分别统计工资记录总数,思路如下:
1、用INNER JOIN连接dept_emp表和salaries表,并以dept_emp.no分组,统计每个部门所有员工工资的记录总数
2、再将上表用INNER JOIN连接departments表,限制条件为两表的dept_no相等,找到dept_no与dept_name的对应关系,最后依次输出dept_no、dept_name、sum
23、对所有员工的当前(to_date='9999-01-01')薪水按照salary进行按照1-N的排名,相同salary并列且按照emp_no升序排列
数据库表:
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
题解:
语法注释:
(未完待更新)