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')
Last modification:May 11th, 2020 at 10:58 am