牛客-SQL-刷题(下)

上是一些基本操作回顾

按照牛客上的通过率,下应该难一点

31. 使用join查询方式找出没有分类的电影id以及名称

film表
字段 说明
film_id 电影id
title 电影名称
description 电影描述信息

category表

字段 说明
category_id 电影分类id
name 电影分类名称
last_update 电影分类最后更新时间

film_category表

字段 说明
film_id 电影id
category_id 电影分类id
last_update 电影id和分类id对应关系的最后更新时间

分析:film_id在film表中,但不在film_category表中
SELECT a.film_id, a.title FROM film a
LEFT JOIN film_category b
ON a.film_id=b.film_id
WHERE b.film_id is NULL;

32. 将employees表的所有员工的last_name和first_name拼接起来作为Name,中间以一个空格区分

      分析:考察SQLite中字符串的拼接 ‘||’

SELECT last_name || ' ' || first_name name FROM employees;

33. 查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工

      分析:考察LEFT JOIN,左表有的记录都会展现出来,不论右表有没有

SELECT a.last_name, a.first_name, b.dept_no FROM employees a
LEFT JOIN dept_emp b
ON a.emp_no=b.emp_no;

34. 查找所有已经分配部门的员工的last_name和first_name以及dept_no

      分析:主键emp_no在dept_emp中,以dept_emp作为左表

SELECT b.last_name, b.first_name, a.dept_no FROM dept_emp a
LEFT JOIN employees b
ON a.emp_no=b.emp_no;

35. 现在在last_update后面新增加一列名字为create_date, 类型为datetime, NOT NULL,默认值为'0000 00:00:00'

      分析:知识盲区:设置默认值DEFAULT 在创建表时就应该注意到了

ALTER TABLE actor ADD create_date datetime NOT NULL DEFAULT '0000-00-00 00:00:00';

36. 获取所有员工的emp_no、部门编号dept_no以及对应的bonus类型btype和received ,没有分配具体的员工不显示

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`));
CREATE TABLE `emp_bonus`(`emp_no` int not null,`recevied` datetime not null,`btype` smallint not null);

      分析:btype, received选自emp_bonus表,dept_no选自dept_emp表,二者用emp_no连接起来

               因为dep_emp表中的emp_no $subset$ employees表中的emp_no,所以不需要再连接筛选一遍

SELECT a.emp_no,a.dept_no, b.btype,b.recevied FROM dept_emp a
LEFT JOIN emp_bonus b
ON a.emp_no=b.emp_no;

注意:牛客后台emp_bonus中是recevied,不是recevied

37. 按照salary的累计和running_total,其中running_total为前两个员工的salary累计和,其他以此类推。

      分析:整懵了,参考他人的题解:running_total给出的应该是前面所有员工的salary之和

                 把当前的emp_no和所有<=emp_no的连接起来,计算sum,根据当前的emp_no分类

                 注意是当前的salary,所以有to_date='9999-01-01'

SELECT a.emp_no, a.salary, sum(b.salary) running_total 
FROM salaries a, salaries b
WHERE b.emp_no<=a.emp_no AND a.to_date='9999-01-01' AND b.to_date='9999-01-01'
GROUP BY a.emp_no;

 38. 对于employees表中,给出奇数行的first_name

      分析:同上,用两个表连接,以b.first_name<=a.first_name的count(*)作为序列号

                注意:这里比较的是字符串,不是b.emp_no<=a.emp_no

参考:SQL语句查询结果额外添加一列序号自动增加

https://www.cnblogs.com/tiantianne/archive/2009/10/13/1582368.html

SELECT first_name FROM employees a
WHERE(SELECT COUNT(*) FROM employees b
      WHERE b.first_name<=a.first_name)%2=1;

 39. 统计出当前各个title类型对应的员工当前(to_date='9999-01-01')薪水对应的平均工资。结果给出title以及平均工资avg。

      分析:用两张表的emp_no连接,根据title分类

SELECT b.title, avg(a.salary) FROM salaries a,titles b
WHERE a.emp_no=b.emp_no AND a.to_date='9999-01-01'AND b.to_date='9999-01-01'
GROUP BY b.title;

40. 统计各个部门的工资记录数,给出部门编码dept_no、部门名称dept_name以及次数sum

      分析:将dept_emp表和salaries表用emp_no连接起来,找次数;从departments表中要dept_name

SELECT b.dept_no, c.dept_name, COUNT(*) FROM salaries a, dept_emp b, departments c
WHERE a.emp_no=b.emp_no AND b.dept_no=c.dept_no
GROUP BY b.dept_no;

41. 获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date='9999-01-01'
      结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no

     分析:dept_emp表和dept_manager表的dept_no相同,这样才是同一个部门的;

                经理的名字在dept_manager中,也在dept_emp中;员工的名字只在dept_emp中

SELECT a.emp_no, b.emp_no manager_no FROM dept_emp a, dept_manager b
WHERE a.dept_no=b.dept_no AND a.emp_no <> b.emp_no AND a.to_date='9999-01-01' AND b.to_date='9999-01-01';

42. 查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工

      分析:两次连用LFET JOIN 

                 注意:不能用WHERE,因为要有没有分配部门的员工

SELECT a.last_name, a.first_name, c.dept_name FROM employees a
LEFT JOIN dept_emp b ON a.emp_no=b.emp_no
LEFT JOIN departments c ON b.dept_no=c.dept_no;

 43. 获取所有部门当前manager的当前薪水情况,给出dept_no, emp_no以及salary,当前表示to_date='9999-01-01'

       分析:两张表用emp_no连接;注意:两张表都需要to_date='9999-01-01'

SELECT a.dept_no, a.emp_no, b.salary FROM dept_manager a, salaries b
WHERE a.emp_no=b.emp_no AND a.to_date='9999-01-01' AND b.to_date='9999-01-01';

44. 获取有奖金的员工相关信息
给出emp_no、first_name、last_name、奖金类型btype、对应的当前薪水情况salary以及奖金金额bonus。
bonus类型btype为1其奖金为薪水salary的10%,btype为2其奖金为薪水的20%,其他类型均为薪水的30%;当前薪水表示to_date='9999-01-01'

分析:先计算获得奖金的emp_no,对应的salary、bonus,用salaries表和emp_bonus表
           再找出emp_no对应的first_name, last_name

知识盲区:CASE 列名
                  WHEN 列值1 THEN ...
                  WHEN 列值2 THEN ...
                  ELSE ... END

或者是

                  CASE 
                  WHEN 列名=条件1 THEN ...
                  WHEN 列名=条件2 THEN ...
                  ELSE ... END

SELECT e.emp_no,e.first_name,e.last_name,b.btype,s.salary,
(CASE b.btype 
WHEN 1 THEN s.salary*0.1
WHEN 2 THEN s.salary*0.2
ELSE s.salary*0.3 END) bonus
FROM employees e, emp_bonus b, salaries s
WHERE b.emp_no=e.emp_no AND s.emp_no=b.emp_no AND s.to_date='9999-01-01';

45. 给出每个员工每年薪水涨幅超过5000的员工编号emp_no、薪水变更开始日期from_date以及薪水涨幅值salary_growth,并按照salary_growth逆序排列

      提示:在sqlite中获取datetime时间对应的年份函数为strftime('%Y', to_date)

 
欲望才是原动力
原文地址:https://www.cnblogs.com/Nooni/p/12680587.html