21 查找所有员工自入职以来的薪水涨幅情况
21.1 题目描述
查找所有员工自入职以来的薪水涨幅情况,给出员工编号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`));
21.2 题解
select
start_sal.emp_no
,(end_sal.salary - start_sal.salary) growth
from
(-- 1 入职时的工资
select
e.emp_no
,salary
from
employees e
,salaries s
where
e.emp_no = s.emp_no
and
s.from_date = e.hire_date) start_sal
inner join
(-- 2 最高的工资
select
e.emp_no
,salary
from
employees e
,salaries s
where
e.emp_no = s.emp_no
and
s.to_date = '9999-01-01') end_sal
on
start_sal.emp_no = end_sal.emp_no
order by
growth asc
22 统计各个部门的工资记录数
22.1 题目描述
统计各个部门的工资记录数,给出部门编码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`));
22.2 题解
select
t1.dept_no
,t1.dept_name
,count(t3.salary)
from
departments t1
left join
dept_emp t2
on
t1.dept_no = t2.dept_no
left join
salaries t3
on
t2.emp_no = t3.emp_no
group by
t1.dept_no
23* 对所有员工的薪水按照salary进行按照1-N的排名
23.1 题目描述
对所有员工的当前(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`));
23.2 题解
- 一般题解
-- 计算排名,用两张salaries表,不用表连接
-- 1、从两张相同的salaries表(分别为s1与s2)进行对比分析,先将两表限定条件设为to_date = '9999-01-01',挑选出当前所有员工的薪水情况。
-- 2、本题的精髓在于 s1.salary <= s2.salary,意思是在输出s1.salary的情况下,有多少个s2.salary大于等于s1.salary,比如当s1.salary=94409时,有3个s2.salary(分别为94692,94409,94409)大于等于它,但由于94409重复,利用COUNT(DISTINCT s2.salary)去重可得工资为94409的rank等于2。其余排名以此类推。
-- 3、千万不要忘了GROUP BY s1.emp_no,否则输出的记录只有一条(可能是第一条或者最后一条,根据不同的数据库而定),因为用了合计函数COUNT()
-- 4、最后先以 s1.salary 逆序排列,再以 s1.emp_no 顺序排列输出结果
select
s1.emp_no
,s1.salary
,count(distinct s2.salary) as rank
from
salaries s1
, salaries s2
where
s1.salary <= s2.salary
and
s1.to_date = '9999-01-01'
and
s2.to_date = '9999-01-01'
group by
s1.emp_no
order by
rank
- ==支持
ROW_NUMBER
、RANK
、DENSE_RANK
等函数的SQL Server数据库中,有以下参考代码==
SELECT
emp_no
, salaries
, DENSE_RANK() OVER(ORDER BY salary DESC) AS rank
WHERE
to_date = '9999-01-01'
ORDER BY
salary DESC
, emp_no ASC
24 获取所有非manager员工当前的薪水情况
24.1 题目描述
获取所有非manager员工当前的薪水情况,给出dept_no、emp_no以及salary ,当前表示to_date='9999-01-01'
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`));
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`));
24.2 题解
-- 2 找到所有员工的的薪水
select
t2.dept_no
,t1.emp_no
,t3.salary
from
employees t1
left join
dept_emp t2
on
t1.emp_no = t2.emp_no
left join
salaries t3
on
t2.emp_no = t3.emp_no
where
t3.to_date = '9999-01-01'
and
t1.emp_no not in
(-- 1 找出当前manager的emp_no
select
emp_no
from
dept_manager
where
to_date = '9999-01-01')
25 获取员工其当前的薪水比其manager当前薪水还高的相关信息
25.1 题目描述
获取员工其当前的薪水比其manager当前薪水还高的相关信息,当前表示to_date='9999-01-01',
结果第一列给出员工的emp_no,
第二列给出其manager的manager_no,
第三列给出该员工当前的薪水emp_salary,
第四列给该员工对应的manager当前的薪水manager_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 `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`));
25.2 题解
select
emp_no
,manager_no
,emp_salary
,manager_salary
from
(-- 当前员工的emp_no, salary, dept_no
select
s.emp_no as emp_no
,salary as emp_salary
,dept_no
from
salaries s
,dept_emp d
where
s.emp_no = d.emp_no
and
s.to_date = '9999-01-01'
and
d.to_date = '9999-01-01') tmp_emp
,(-- 当前经理的emp_no, salary, dept_no
select
s.emp_no as manager_no
,salary as manager_salary
,dept_no
from
salaries s
,dept_manager d
where
s.emp_no = d.emp_no
and
s.to_date = '9999-01-01'
and
d.to_date = '9999-01-01') tmp_mng
where
tmp_emp.dept_no = tmp_mng.dept_no
and
tmp_emp.emp_salary > tmp_mng.manager_salary
本题主要思想是创建两张表(一张记录当前所有员工的工资,另一张只记录部门经理的工资)进行比较,具体思路如下:
1、先用INNER JOIN连接salaries和demp_emp,建立当前所有员工的工资记录tmp_emp
2、再用INNER JOIN连接salaries和demp_manager,建立当前所有员工的工资记录tmp_mng
3、最后用限制条件tmp_emp.dept_no = tmp_mng.dept_no AND tmp_emp.salary > tmp_mng.salary找出同一部门中工资比经理高的员工,并根据题意依次输出emp_no、manager_no、emp_salary、manager_salary
26 汇总各个部门当前员工的title类型的分配数目
26.1 题目描述
汇总各个部门当前员工的title类型的分配数目,结果给出部门编号dept_no、dept_name、其当前员工所有的title以及该类型title对应的数目count
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 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);
26.2 题解
select
d1.dept_no as dept_no
,d1.dept_name as dept_name
,t1.title title
,count(*) as count
from
departments d1
,dept_emp d2
,titles t1
where
d1.dept_no = d2.dept_no
and
d2.emp_no = t1.emp_no
and
d2.to_date = '9999-01-01'
and
t1.to_date = '9999-01-01'
group by
d1.dept_no
,t1.title
- 主要就是对两个条件的分组,然后计数
27* 给出每个员工每年薪水涨幅超过5000的员工编号emp_no
27.1 题目描述
给出每个员工每年薪水涨幅超过5000的员工编号emp_no、薪水变更开始日期from_date以及薪水涨幅值salary_growth,并按照salary_growth逆序排列。
提示:在sqlite中获取datetime时间对应的年份函数为strftime('%Y', to_date)
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`));
27.2 题解
-- 1 salaries笛卡尔积 找到薪水涨幅>5000的记录
select
s2.emp_no
,s2.from_date
,(s2.salary - s1.salary) as salary_growth
from
salaries s1
,salaries s2
where
s1.emp_no = s2.emp_no
and
salary_growth > 5000
and
(strftime("%Y",s2.to_date) - strftime("%Y",s1.to_date) = 1 )
order by
salary_growth desc
- 解题思路
链接:https://www.nowcoder.com/questionTerminal/eb9b13e5257744db8265aa73de04fd44
来源:牛客网
本题的难点在于如何理解 每年薪水涨幅,以及复用salaries表求出每年薪水涨幅超过5000的员工,具体思路如下:
1、假设s1是涨薪水前的表,s2是涨薪水后的表,因为每个员工涨薪水的时间不全固定,有可能一年涨两次,有可能两年涨一次,所以每年薪水的涨幅,应该理解为两条薪水记录的from_date相同或to_date相同。
/** 如果只限定to_date相同,则将第三条原始测试数据的52668改成62668时,就会少一条【62668-48584=14084】的记录
INSERT INTO salaries VALUES(10008,46671,'1998-03-11','1999-03-11');
INSERT INTO salaries VALUES(10008,48584,'1999-03-11','2000-03-10');
INSERT INTO salaries VALUES(10008, 62668 ,'2000-03-10','2000-07-31'); **/
2、找到s1与s2符合要求的记录后,用s2的薪水减去s1的薪水,用salary_growth表示,加上限定条件 s1.emp_no = s2.emp_no AND salary_growth > 5000,即同一员工每年涨幅超过5000的记录
3、最后依次输出emp_no、from_date、salary_growth,并以salary_growth逆序排列
28 查找描述信息中包括robot的电影对应的分类名称以及电影数目,而且还需要该分类对应电影数量>=5
28.1 题目描述
film表
字段 | 说明 |
---|---|
film_id | 电影id |
title | 电影名称 |
description | 电影描述信息 |
CREATE TABLE IF NOT EXISTS film (
film_id smallint(5) NOT NULL DEFAULT '0',
title varchar(255) NOT NULL,
description text,
PRIMARY KEY (film_id));
category表
字段 | 说明 |
---|---|
category_id | 电影分类id |
name | 电影分类名称 |
last_update | 电影分类最后更新时间 |
CREATE TABLE category (
category_id tinyint(3) NOT NULL ,
name varchar(25) NOT NULL,
last_update
timestamp,PRIMARY KEY ( category_id ));
film_category表
字段 | 说明 |
---|---|
film_id | 电影id |
category_id | 电影分类id |
last_update | 电影id和分类id对应关系的最后更新时间 |
CREATE TABLE film_category (
film_id smallint(5) NOT NULL,
category_id tinyint(3) NOT NULL,
last_update
timestamp);
查找描述信息中包括robot的电影对应的分类名称以及电影数目,而且还需要该分类对应电影数量>=5部
28.2 题解
select
tmp3.name
,count(*)
from
film tmp1
,film_category tmp2
,category tmp3
,(-- 先找出电影数量>5的category
select
category_id
,count(*) count
from
film_category
group by
category_id
having
count >= 5) tmp4
where
tmp1.film_id = tmp2.film_id
and
tmp2.category_id = tmp3.category_id
and
tmp3.category_id = tmp4.category_id
and
tmp1.description like '%robot%'
group by
tmp3.name
- 这道题目的题意需要明确:==这题有一个陷阱,电影数目>=5 是这类电影的所有数目,并不是包含了robot的这类电影的数目。==
29 使用join查询方式找出没有分类的电影id以及名称
29.1 题目描述
film表
字段 | 说明 |
---|---|
film_id | 电影id |
title | 电影名称 |
description | 电影描述信息 |
CREATE TABLE IF NOT EXISTS film (
film_id smallint(5) NOT NULL DEFAULT '0',
title varchar(255) NOT NULL,
description text,
PRIMARY KEY (film_id));
category表
字段 | 说明 |
---|---|
category_id | 电影分类id |
name | 电影分类名称 |
last_update | 电影分类最后更新时间 |
CREATE TABLE category (
category_id tinyint(3) NOT NULL ,
name varchar(25) NOT NULL,
last_update
timestamp,PRIMARY KEY ( category_id ));
film_category表
字段 | 说明 |
---|---|
film_id | 电影id |
category_id | 电影分类id |
last_update | 电影id和分类id对应关系的最后更新时间 |
CREATE TABLE film_category (
film_id smallint(5) NOT NULL,
category_id tinyint(3) NOT NULL,
last_update
timestamp);
使用join查询方式找出没有分类的电影id以及名称
29.2 题解
select
film_id
,title
from
film
where
film_id not in (
-- 1 以film_category为主要驱动表,找到有分类的film_id
select
fc.film_id
from
film_category fc
left join
film f
on
fc.film_id = f.film_id)
30 使用子查询的方式找出属于Action分类的所有电影对应的title,description
30.1 题目描述
film表
字段 | 说明 |
---|---|
film_id | 电影id |
title | 电影名称 |
description | 电影描述信息 |
CREATE TABLE IF NOT EXISTS film (
film_id smallint(5) NOT NULL DEFAULT '0',
title varchar(255) NOT NULL,
description text,
PRIMARY KEY (film_id));
category表
字段 | 说明 |
---|---|
category_id | 电影分类id |
name | 电影分类名称 |
last_update | 电影分类最后更新时间 |
CREATE TABLE category (
category_id tinyint(3) NOT NULL ,
name varchar(25) NOT NULL,
last_update
timestamp,PRIMARY KEY ( category_id ));
film_category表
字段 | 说明 |
---|---|
film_id | 电影id |
category_id | 电影分类id |
last_update | 电影id和分类id对应关系的最后更新时间 |
CREATE TABLE film_category (
film_id smallint(5) NOT NULL,
category_id tinyint(3) NOT NULL,
last_update
timestamp);
使用子查询的方式找出属于Action分类的所有电影对应的title,description
30.2 题解
select
title
,description
from
film
where
film_id in (
-- 1 以film_category为主要驱动表,找到Action分类的film_id
select
fc.film_id
from
film_category fc
left join
film f
on
fc.film_id = f.film_id
left join
category c
on
fc.category_id = c.category_id
where
c.name = 'Action')