牛客网SQL实战二刷 | Day10

「牛客网SQL实战二刷」是个系列学习笔记博文,今天解析7道SQL题目~ 第55 - 61题。

每篇笔记的格式大致为,三大板块:

  • 大纲
  • 题目(题目描述、思路、代码、相关参考资料/答疑)
  • 回顾

❤️「往期回顾」

《牛客网SQL实战二刷 | 完整解析 – 目录索引》


一、大纲
题号知识点
55LIMIT,OFFSET
56LEFT JOIN
57NOT EXISTS
58求交集
59CASE WHEN
60表复用计算累加和
61表复用计算行数

二、题目

55. 分页查询employees表,每5行一页,返回第2页的数据

  • 题目描述

分页查询employees表,每5行一页,返回第2页的数据

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`));
  • 思路

转化一下题意,「每5行一页,返回第2页的数据」,即返回第6~10条记录,用LIMIT 搭配 OFFSET 使用。

  • 代码
SELECT * FROM employees LIMIT 5 OFFSET 5;

?Limit 与offset

举个例子,LIMIT 3 OFFSET 1, 这意味着,跳过第1条记录(即从第2条记录开始),返回接下来3条记录。即最终得到,原本的第2,3,4条记录。

  • 举一反三

牛客网SQL实战二刷 | Day1》第2题。

  • 参考资料

《SQLite Limit 子句》https://www.runoob.com/sqlite/sqlite-limit-clause.html


56. 获取所有员工的emp_no

  • 题目描述

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

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 emp_bonus(
emp_no int not null,
recevied datetime not null,
btype smallint not null);
  • 输出描述
e.emp_nodept_nobtyperecevied
10001d00112010-01-01
10002d00122010-10-01
10003d00432011-12-03
10004d00412010-01-01
10005d003
10006d002
10007d005
10008d005
10009d006
  • 思路

表dept_emp 左连接 表emp_bonus。

  • 代码
SELECT de.emp_no, de.dept_no, eb.btype, eb.recevied
FROM dept_emp AS de LEFT JOIN emp_bonus AS eb ON 
de.emp_no = eb.emp_no;

57. 使用含有关键字exists查找未分配具体部门的员工的所有信息。

  • 题目描述

使用含有关键字exists查找未分配具体部门的员工的所有信息。

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 `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`));
  • 输出描述
emp_nobirth_datefirst_namelast_namegenderhire_date
100111953-11-07MarySluisF1990-01-22
  • 思路
  • 本题用 EXISTS 关键字的方法如下:意为在 employees 中挑选出令(SELECT emp_no FROM dept_emp WHERE emp_no = employees.emp_no)不成立的记录,也就是当 employees.emp_no=10011的时候。反之,把NOT去掉,则输出 employees.emp_no=10001~10010时的记录。
  • 由于 OJ系统没有限制我们只能使用 EXISTS 关键字,因此还能用 NOT IN 关键字替换,即在employees 中选出 dept_emp 中没有的 emp_no。

作者:wasrehpic
来源:https://www.nowcoder.com/questionTerminal/c39cbfbd111a4d92b221acec1c7c1484?f=discussion

  • 代码
  1. 方法一、NOT EXISTS
SELECT * FROM employees 
WHERE NOT EXISTS (SELECT emp_no FROM dept_emp WHERE emp_no = employees.emp_no)
  1. 方法二、NOT IN
SELECT * FROM employees 
WHERE emp_no NOT IN (SELECT emp_no FROM dept_emp)

58. 获取employees中的行数据,且这些行也存在于emp_v中

  • 题目描述

存在如下的视图:

create view emp_v as select * from employees where emp_no >10005;
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`));

获取employees中的行数据,且这些行也存在于emp_v中。注意不能使用intersect关键字。

  • 输出描述
emp_nobirth_datefirst_namelast_namegenderhire_date
100061953-04-20AnnekePreusigF1989-06-02
100071957-05-23TzvetanZielinskiF1989-02-10
100081958-02-19SaniyaKalloufiM1994-09-15
100091952-04-19SumantPeacF1985-02-18
100101963-06-01DuangkaewPiveteauF1989-08-24
100111953-11-07MarySluisF1990-01-22
  • 思路

根据题意,不能使用 INTERSECT 关键字,但由于视图 emp_v 的记录是从 employees 中导出的,因此要判断两者中相等的数据,只需要判断emp_no相等即可。

  • 方法一:用 WHERE 选取二者 emp_no 相等的记录
  • 方法二:由于emp_v的全部记录均由 employees 导出,因此可以投机取巧,直接输出 emp_v 所有记录
  • 代码
  1. 方法一
SELECT em.* FROM employees AS em, emp_v AS ev WHERE em.emp_no = ev.emp_no; 
  1. 方法二
SELECT * FROM emp_v;
  1. 方法三:OJ系统限制了,但是如果用INTERSECT实现
SELECT * FROM emp_v INTERSECT SELECT * FROM employees
  • 举一反三

牛客网SQL实战二刷 | Day8》第47题。


59. 获取有奖金的员工相关信息。

  • 题目描述

获取有奖金的员工相关信息。

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


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`));

给出emp_no、first_name、last_name、奖金类型btype、对应的当前薪水情况salary以及奖金金额bonus。 bonus类型btype为1其奖金为薪水salary的10%,btype为2其奖金为薪水的20%,其他类型均为薪水的30%。 当前薪水表示to_date=‘9999-01-01’

  • 思路

用CASE WHEN条件判断。

  • 输出描述
emp_nofirst_namelast_namebtypesalarybonus
10001GeorgiFacello1889588895.8
10002BezalelSimmel27252714505.4
10003PartoBamford34331112993.3
10004ChirstianKoblick1740577405.7
  • 代码
SELECT e.emp_no, e.first_name, e.last_name, eb.btype, s.salary,
(CASE eb.btype
    WHEN 1 THEN 0.1 * s.salary
    WHEN 2 THEN 0.2 * s.salary
    ELSE 0.3 * s.salary 
END ) AS bonus
FROM employees AS e INNER JOIN emp_bonus AS eb ON e.emp_no = eb.emp_no
INNER JOIN salaries AS s ON e.emp_no = s.emp_no AND s.to_date = '9999-01-01' 

?CASE WHEN

Case具有两种格式。简单Case函数和Case搜索函数。

--简单Case函数
SELECT  SUM(population), 
    CASE (country  
        WHEN '中国' THEN '亚洲' 
        WHEN '印度' THEN '亚洲' 
        WHEN '日本' THEN '亚洲' 
        WHEN '美国' THEN '北美洲' 
        WHEN '加拿大'  THEN '北美洲' 
        WHEN '墨西哥'  THEN '北美洲' 
        ELSE '其他' 
    END) 
FROM    Table_A 


--Case搜索函数

UPDATE Personnel
SET salary =
CASE (WHEN salary >= 5000  THEN salary * 0.9
     	WHEN salary >= 2000 AND salary < 4600  THEN salary * 1.15
		ELSE salary END); 

-- 用一个SQL语句完成不同条件的分组

SELECT country, 
    SUM( CASE WHEN sex = '1' THEN  population ELSE 0 END),  --男性人口 
    SUM( CASE WHEN sex = '2' THEN  population ELSE 0 END)   --女性人口
FROM  Table_A  GROUP BY country;
  • 强烈参考

《【SQL】SQL中Case When的用法》https://www.cnblogs.com/HDK2016/p/8134802.html


?60. 统计salary的累计和running_total

  • 题目描述

按照salary的累计和running_total,其中running_total为前两个员工的salary累计和,其他以此类推。 具体结果如下Demo展示。。

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`));
  • 输出描述
emp_nosalaryrunning_total
100018895888958
1000272527161485
1000343311204796
1000474057278853
1000594692373545
1000643311416856
1000788070504926
1000995409600335
1001094409694744
1001125828720572
  • 思路

复用 表salaries,限制s1的emp_no小于等于 s2的emp_no,再对s1的工资求和,即相当于累加。

  • 代码
SELECT s2.emp_no, s2.salary, SUM(s1.salary) AS running_total
FROM salaries AS s1 INNER JOIN salaries AS s2
ON s1.emp_no <= s2.emp_no
WHERE s1.to_date = '9999-01-01' AND s2.to_date = '9999-01-01'
GROUP BY s2.emp_no

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

  • 题目描述

对于employees表中,给出奇数行的first_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`));
  • 输出描述
first_name
Georgi
Chirstian
Anneke
Tzvetan
Saniya
Mary
  • 思路
  1. 和上一题相似的地方在于,也是表的复用,其实相当于我们自己写了语句计算row numbers;
  2. 「奇数行」,即行数除以2余1。
  • 代码
SELECT e1.first_name FROM employees AS e1
WHERE (SELECT COUNT(*) FROM employees AS e2
      WHERE e1.first_name <= e2.first_name)%2 == 1;

?SQLITE 创建rownumber

  1. 原表
    http://www.onbno.com/ruanjiajiqiao/sqlite-none-row-number.html
  2. 插入rownumber 代码实现
SELECT
 ( SELECT COUNT(distinct id)  FROM  [file] AS t2  WHERE t2.id <= t1.id) AS rowNum, id,  name 
 FROM [file] t1 
 ORDER BY  t1.id asc
  1. 新表

http://www.onbno.com/ruanjiajiqiao/sqlite-none-row-number.html
来源:http://www.onbno.com/ruanjiajiqiao/sqlite-none-row-number.html

  • 强烈推荐

《sqlite没有行号(rownumber)的解决办法》 http://www.onbno.com/ruanjiajiqiao/sqlite-none-row-number.html


三、回顾
知识点题号
LIMIT,OFFSET55
表连接56
NOT EXISTS57
求交集58
CASE WHEN59
表复用60,61

? 写在最后

Day10 是「牛客网SQL实战二刷」系列最后一天啦。坚持就是胜利,欧耶✌️

比起第一次做SQL题库,这次在前半部分查询语句的方面,明显进步很多。很多时候直接上手敲,就能通过了。不过,后半部分,大概从Day6开始,虽然代码变得短小和简单了,但是反而不那么熟悉,往往要辅助资料,也能敲出来。但我相信,这次「二刷题库」扎实了我的基础。

通过我做「真题」的体验,「数据库管理和操作」对「数据分析岗」真是非常非常非常关键和重要的了,是基础也是必须。真题里的SQL操作,结合上业务需要,比起题库里的题更具有应用性,比如「拼多多2020数据分析师真题」。我依旧有很多没见过的需求,我还有很多不会的和要掌握的。

可能还会三刷,可能接下来偏向分享「来源于真题中的,有业务背景的,对真实需求对数据库操作」。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值