记录一下刷题时候的解题思路和方法
目录
3.查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_no
4.查找所有已经分配部门的员工的last_name和first_name以及dept_no
5.查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括暂时没有分配具体部门的员工
6.查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序(请注意,一个员工可能有多次涨薪的情况)
7.查找薪水变动超过15次的员工号emp_no以及其对应的变动次数t
8.找出所有员工当前(to_date='9999-01-01')具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示
13.从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。
15.查找employees表所有emp_no为奇数,且last_name不为Mary(注意大小写)的员工信息,并按照hire_date逆序排列(题目不能使用mod函数)
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(可能有多次涨薪,没有降薪)
1.查找最晚入职员工的所有信息
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`));
思路:1.找到入职hire_date最晚的日期2.找到最晚日期对应的所有职工
select * from employees
where hire_date=(select max(hire_date) from employees)
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`));
思路:1.对入职日期按降序排列
2.查询结果限制从第2个元素开始输出(编号从0开始),输出一个元素
select *from employees
order by hire_date desc limit 2,1
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 salaries.*, dept_manager.dept_no
from salaries , dept_manager
where salaries.to_date='9999-01-01'
and dept_manager.to_date='9999-01-01'
and salaries.emp_no=dept_manager.emp_no;
思路:查询的内容在两张表里面,所以要用到多表连接,这里使用内连接即可,因为两表均有emp_no字段,所以where连接判断时取两表相等时判断。此外还要考虑题目要求
4.查找所有已经分配部门的员工的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 employees.last_name,employees.first_name,dept_emp.dept_no
from employees,dept_emp
where employees.emp_no=dept_emp.emp_no
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 as e left join dept_emp as d
on d.emp_no=e.emp_no
考察“左外连接”,在查询时,左边的表全部保留,如果左边表没有右边表中的元素,则为空
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 employees.emp_no,salaries.salary
from employees,salaries
where employees.emp_no=salaries.emp_no and employees.hire_date=salaries.from_date
order by employees.emp_no desc
这个题目的陷阱就是,你需要设置条件,查询所有人的入职时候的薪水,也即将薪水表的from_date日期设置为员工表的hire_date入职日期
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`));
变动次数有点难想,我也是看了评论才有思路的:将数据按照emp_no字段分成若干组,每组对应了相同的emp_no,每组的长度就是不同的salary长度(这里不考虑salary字段是否有相等值,只考虑记录数)。分组的化就用到了group by关键字, 可参考中https://www.runoob.com/sql/sql-groupby.html对group by的详细描述。分组后用having 关键字筛选数据。
这里as关键字的作用是:当我们想认为指定一个不存在的列或修改原有的列名,可以通过as关键字设置。
select emp_no,count(emp_no) as t
from salaries
group by emp_no
having t>15
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 distinct salary
from salaries
where to_date='9999-01-01'
order by salary desc
考点:distinct关键字,在表中,一个列可能会包含多个重复值,仅仅列出不同的值时,用distinct区分。
9.获取所有部门当前(dept_manager.to_date='9999-01-01')manager的当前(salaries.to_date='9999-01-01')薪水情况,给出dept_no, emp_no以及salary(请注意,同一个人可能有多条薪水情况记录)
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 dept_manager.dept_no,dept_manager.emp_no,salaries.salary
from dept_manager,salaries
where dept_manager.emp_no=salaries.emp_no
and dept_manager.to_date='9999-01-01'
and salaries.to_date='9999-01-01'
这题简单,考察and多条件连接
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`));
select emp_no
from employees
where emp_no not in (select emp_no from dept_manager)
考察in关键字,in关键字用在where里作为筛选条件之一。
A in B 表示 前者在后者中,A not in B表示A不在B中
(select emp_no from dept_manager)表示的先从dept_manager表中将经理的员工号选出来。
用not in 排除到经理
11.获取所有员工当前的(dept_manager.to_date='9999-01-01')manager,如果员工是manager的话不显示(也就是如果当前的manager是自己的话结果不显示)。输出结果第一列给出当前员工的emp_no,第二列给出其manager对应的emp_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 dept_emp.emp_no,dept_manager.emp_no as manager_no
from dept_emp,dept_manager
where dept_emp.dept_no=dept_manager.dept_no
and dept_emp.emp_no not in (select emp_no from dept_manager)
and dept_manager.to_date='9999-01-01'
这是在上题的基础上考虑了多条件查询,增加了一个where判断
12.获取所有部门中当前(dept_emp.to_date = '9999-01-01')员工当前(salaries.to_date='9999-01-01')薪水最高的相关信息,给出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 dept_emp.dept_no,dept_emp.emp_no,max(salaries.salary)
from dept_emp inner join salaries on dept_emp.emp_no=salaries.emp_no
and dept_emp.to_date='9999-01-01' and salaries.to_date='9999-01-01'
group by dept_no
或者
select dept_emp.dept_no,dept_emp.emp_no,max(salaries.salary)
from dept_emp, salaries
where dept_emp.emp_no=salaries.emp_no
and dept_emp.to_date='9999-01-01' and salaries.to_date='9999-01-01'
group by dept_no
对部门按照部门编号dept_no进行分组,每组中选出工资最大的员工信息。
考察点group by和聚合函数Max的适用
两表可以适用表A inner join 表B实现,或者用where和=连接实现
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(emp_no) as t
from titles
group by title
having t>=2
再次考察group by 函数和having相结合,对数据进行分组。
在SQL中增加having子句的原因是,where关键字无法与聚合函数一起使用,一起判断。having子句可以让我们筛选分组后的各组数据。
14.从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。
注意对于重复的emp_no进行忽略(即emp_no重复的title不计算,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(distinct emp_no) as t
from titles
group by title
having t>=2
与上题区别在于 group by +having +distinct去重函数组合使用
15.查找employees表所有emp_no为奇数,且last_name不为Mary(注意大小写)的员工信息,并按照hire_date逆序排列(题目不能使用mod函数)
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 is not 'Mary'
order by hire_date desc
emp_no % 2=1也可以改成MOD(emp_no, 2)=1,但是某些sql版本可能不支持后者(比如题库就不支持)
补充:不相等有三种表示方式:<>、!=、IS NOT
注意:last_name是varchar类型,所以对它的判断需要加上单引号
16.统计出当前(titles.to_date='9999-01-01')各个title类型对应的员工当前(salaries.to_date='9999-01-01')薪水对应的平均工资。结果给出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 title,avg(salary) as avg
from salaries,titles
where salaries.emp_no=titles.emp_no
and titles.to_date='9999-01-01' and salaries.to_date='9999-01-01'
group by title
考察了一个avg函数求平均值,各个title类型对应的员工 group by title
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 to_date='9999-01-01'
order by salary desc limit 1,1
子查询+order by
desc 按照工资下降的顺序排序
limit 1,1表示从序列为1的元素开始输出第一个元素。这里sql是从0开始作为起始下标
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 s.emp_no,s.salary,e.last_name,e.first_name
from employees e inner join salaries s on e.emp_no=s.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'
)
尝试用inner join on 而不是where = 进行两表连接。
这题思路是两次最大salary选择,最里面的第一次max,目的是选择进行过滤,将最大的那个排除。
第二次最大是从过滤后的salaries表中选择最大的。即完成了从原表中选择第二大。
有了这个思路,我们可以将外循环的select max写到最开始的地方,参加下面代码
select s.emp_no, max(salary),e.last_name,e.first_name
from employees e inner join salaries s on e.emp_no=s.emp_no
where salary <
(
select max(salary) from salaries where to_date='9999-01-01'
)
and to_date='9999-01-01'
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 e.last_name,e.first_name,d.dept_name
from (employees e left join dept_emp de on de.emp_no=e.emp_no)
left join departments d on d.dept_no=de.dept_no
考察:
1.多表连接:题目给了三个表,查询的内容在departments表和employees表中,但是两表不能直接连接,要借助dept_emp表建立起关系。
2.左外连接:题目要求dept信息可以空着,但是必须有员工信息,因此,建立连接时employees表必须最先考虑。
而dept_emp由于起承接性自然还是放在中间,
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`));
思路:考察SQL函数部分的max函数和min函数
查询该员工最高工资和最低工资,两者的差即growth
复杂一点的可用排序得到最大最小。
select max(salary)-min(salary) as growth
from salaries
where emp_no='10001'