牛客网sql题目总结(三)

21.

  • 题目描述
    对所有员工的当前(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));
  • 题目解答
    本题的主要思想是复用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 AS s1, salaries AS s2
WHERE s1.to_date = '9999-01-01'  AND s2.to_date = '9999-01-01' AND s1.salary <= s2.salary
GROUP BY s1.emp_no
ORDER BY s1.salary DESC, s1.emp_no ASC

22.

  • 题目描述
    获取所有非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));
  • 题目解答
    1、先用JOIN连接employees和salaries,找出当前所有员工的工资情况
    2、再用JOIN连接dept_emp表,找到所有员工所在的部门
    3、最后用限制条件de.emp_no NOT IN (SELECT emp_no FROM dept_manager WHERE to_date = ‘9999-01-01’)选出当前所有非manager员工,再依次输出dept_no、emp_no、salary
SELECT de.dept_no, s.emp_no, s.salary 
FROM (employees AS e JOIN salaries AS s ON s.emp_no = e.emp_no AND s.to_date = '9999-01-01')
JOIN dept_emp AS de ON e.emp_no = de.emp_no
WHERE de.emp_no NOT IN (SELECT emp_no FROM dept_manager WHERE to_date = '9999-01-01')

23.

  • 题目描述
    获取员工其当前的薪水比其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));
  • 题目解答
    本题主要思想是创建两张表(一张记录当前所有员工的工资,另一张只记录部门经理的工资)进行比较,具体思路如下:
    1、先用INNER JOIN连接salaries和demp_emp,建立当前所有员工的工资记录sem
    2、再用INNER JOIN连接salaries和demp_manager,建立当前所有部门经理的工资记录sdm
    3、最后用限制条件sem.dept_no = sdm.dept_no AND sem.salary > sdm.salary找出同一部门中工资比经理高的员工,并根据题意依次输出emp_no、manager_no、emp_salary、manager_salary
SELECT sem.emp_no AS emp_no, sdm.emp_no AS manager_no, sem.salary AS emp_salary, sdm.salary AS manager_salary
FROM (SELECT s.salary, s.emp_no, de.dept_no FROM salaries s INNER JOIN dept_emp de
ON s.emp_no = de.emp_no AND s.to_date = '9999-01-01' ) AS sem, 
(SELECT s.salary, s.emp_no, dm.dept_no FROM salaries s INNER JOIN dept_manager dm
ON s.emp_no = dm.emp_no AND s.to_date = '9999-01-01' ) AS sdm
WHERE sem.dept_no = sdm.dept_no AND sem.salary > sdm.salary

24.

  • 题目描述
    汇总各个部门当前员工的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);

  • 题目解答
    1、先用 INNER JOIN 连接 dept_emp 与 salaries,根据测试数据添加限定条件 de.to_date = ‘9999-01-01’ AND t.to_date = ‘9999-01-01’,即当前员工的当前头衔
    2、再用 INNER JOIN 连接departments,限定条件为 de.dept_no = dp.dept_no,即部门编号相同
    3、最后用 GROUP BY 同时对 de.dept_no 和 t.title 进行分组,用 COUNT(t.title) 统计相同部门下相同头衔的员工个数

SELECT de.dept_no, dp.dept_name, t.title, COUNT(t.title) AS count
FROM titles AS t INNER JOIN dept_emp AS de 
ON t.emp_no = de.emp_no AND de.to_date = '9999-01-01' AND t.to_date = '9999-01-01'
INNER JOIN departments AS dp 
ON de.dept_no = dp.dept_no
GROUP BY de.dept_no, t.title

25.

  • 题目描述
    给出每个员工每年薪水涨幅超过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));

  • 题目解答
    本题的难点在于如何理解 每年薪水涨幅,以及复用salaries表求出每年薪水涨幅超过5000的员工,具体思路如下:
    1、假设s1是涨薪水前的表,s2是涨薪水后的表,因为每个员工涨薪水的时间不全固定,有可能一年涨两次,有可能两年涨一次,所以每年薪水的涨幅,应该理解为两条薪水记录的from_date相同或to_date相同。
    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逆序排列
SELECT s2.emp_no, s2.from_date, (s2.salary - s1.salary) AS salary_growth
FROM salaries AS s1, salaries AS s2
WHERE s1.emp_no = s2.emp_no 
AND salary_growth > 5000
AND (strftime("%Y",s2.to_date) - strftime("%Y",s1.to_date) = 1 
     OR strftime("%Y",s2.from_date) - strftime("%Y",s1.from_date) = 1 )
ORDER BY salary_growth DESC

26.

  • 题目描述
    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表

扫描二维码关注公众号,回复: 1438137 查看本文章

字段 说明
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部

  • 题目解答
    1、找到对应电影数量>=5的所有分类,建立成虚表cc:(select category_id, count(film_id) as category_num from film_category group by category_id having count(film_id)>=5) as cc
    2、设定限制条件 film.description like ‘%robot%’
    3、在表cc、film、film_category、category中查找包括robot的电影对应的分类名称和对应的电影数目。
select category.name,count(film.film_id)
from ((category join film_category on category.category_id=film_category.category_id)as temple
join film on temple.film_id=film.film_id)as tt 
join (select category_id, COUNT(film_id) AS category_num FROM
     film_category  GROUP BY category_id HAVING count(film_id)>=5) AS cc  on tt.category_id=cc.category_id
where film.description LIKE '%robot%'

27.

  • 题目描述
    仍有与26题中相同的film表、category表、film_category表。使用join查询方式找出没有分类的电影id以及名称
  • 题目解答
    解题思路是运用 LEFT JOIN 连接两表,用 IS NULL 语句限定条件:
    1、用 LEFT JOIN 连接 film 和 film_category,限定条件为 f.film_id = fc.film_id,即连接电影 id 和电影分类 id,如果电影没有分类,则电影分类 id 显示 null
    2、再用 WHERE 来限定条件 fc.category_id IS NULL 选出没分类的电影
SELECT f.film_id, f.title FROM film f LEFT JOIN film_category fc
ON f.film_id = fc.film_id WHERE fc.category_id IS NULL

28.

  • 题目描述
    仍有与26题中相同的film表、category表、film_category表。使用子查询的方式找出属于Action分类的所有电影对应的title,description
  • 题目解答
select f.title,f.description
from film f 
where f.film_id in
  (select fc.film_id from film_category fc join category c
       on fc.category_id=c.category_id and c.name='Action')

29.

EXPLAIN SELECT * FROM employees

30.

  • 题目描述
    将employees表的所有员工的last_name和first_name拼接起来作为Name,中间以一个空格区分
    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));
  • 题目解答
    不同数据库连接字符串的方法不完全相同,MySQL、SQL Server、Oracle等数据库支持CONCAT方法,而本题所用的SQLite数据库只支持用连接符号”||”来连接字符串
SELECT last_name||" "||first_name AS Name FROM employees

猜你喜欢

转载自blog.csdn.net/qq_33186949/article/details/80040983