牛客数据库SQL实战 21-30(23_27_表的复用)


欢迎访问笔者个人技术博客: http://rukihuang.xyz/
牛客网数据库SQL实战

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_NUMBERRANKDENSE_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')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值