MySQL基础练习01--牛客网
目录
1 查找最晚入职员工的信息
2 查找入职第三晚的员工信息
3 查找当前薪水详情及部门编号
4 查找所有员工入职时的薪水情况
5 查找已分配员工姓名
6 查找员工姓名
7 查找涨薪找过15次的员工
8 找出所有员工当前薪水情况
9 获取当前部门所有manager的薪水情况
10 获取所有非manager的员工emp_no
11 获取当前员工的manager
12 获取当前薪水最高的员工信息
注:下面的解题中会发现后多INNER JOIN这种内联,其实不用写也没关系的。
1 查找最晚入职员工的信息
题目描述
查找最晚入职员工的所有信息
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`));
输入描述:
无
输出描述:

示例1
输入
无
输出
无
-- 查询语句 LIMIT 1 是LIMIT 0,1 表是从第0条数据开始取1条数据
SELECT * FROM employees ORDER BY hire_date DESC LIMIT 1;
-- 这个语句有问题在于只找到了一条记录,有可能当天会有好多人入职 -- 从表的日期中挑选出最大的就可以避免上述问题了
SELECT * FROM employees WHERE
hire_date=(SELECT MAX(hire_date) FROM employees)
其实对于max也可以用下面的代替:这个和下面查找第三晚的就很类似了
SELECT *
FROM employees
WHERE hire_date=(SELECT hire_date FROM employees ORDER BY hire_date DESC LIMIT 1)
2 查找入职第三晚的员工信息
在上面一个问题的前提下找到第三晚入职的员工
-- distinct 是过滤掉重复的,因为前面的可能日期相同的不止一个,但这样同样会有一个问题
-- 采用下面的方法也是只能挑出来一个信息,当倒数第三个日期有好几个时就会出现错误
SELECT *FROM employees WHERE
hire_date=(SELECT DISTINCT hire_date FROM employees ORDER BY hire_date DESC LIMIT 2,1);
3 查找当前薪水详情及部门编号
题目描述
查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_no
输入描述:
无
输出描述:

-- 根据输出表的信息确定salaries是主表
SELECT s.*,d.dept_no -- 选择salaries表和dept_manager的dept_no列
FROM salaries AS s JOIN dept_manager AS d -- 两个as相当于对表重命名,所以一开始才可以直接用s和d表示两个表
ON s.emp_no=d.emp_no -- on在创建临时表的限制条件,一般两个表链接时多用
WHERE s.to_date='9999-01-01' AND d.to_date='9999-01-01' -- 临时表生成后的限制
-- 执行顺序为先 on再where -- 可以用下面这个代码试试会产生什么情况
SELECT d.*,s.salary FROM salaries AS s JOIN dept_manager AS d
ON s.emp_no=d.emp_no
WHERE s.to_date='9999-01-01' AND d.to_date='9999-01-01'

上面的代码但在实际开发中是不推荐使用的,因为数据库在使用中应尽量减少物理连接,使用逻辑连接,因此多使用where语句来完成关联,此外使用where在性能上也要比使用join连接快
SELECT s.*,d.dept_no
FROM salaries AS s, dept_manager AS d
WHERE s.emp_no = d.emp_no
AND s.to_date='9999-01-01'
AND d.to_date='9999-01-01'
4 查找所有员工入职时的薪水情况
题目描述
查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序
输入描述:
无
输出描述:

/*
此题应注意以下四个知识点:
1、由于测试数据中,salaries.emp_no 不唯一(因为号码为 emp_no 的员工会有多次涨薪的可能,所以在 salaries 中对应的记录不止一条),employees.emp_no 唯一,即 salaries 的数据会多于 employees,因此需先找到 employees.emp_no 在 salaries 表中对应的记录salaries.emp_no,则有限制条件 e.emp_no = s.emp_no
2、根据题意注意到 salaries.from_date 和 employees.hire_date 的值应该要相等,因此有限制条件 e.hire_date = s.from_date
3、根据题意要按照 emp_no 值逆序排列,因此最后要加上 ORDER BY e.emp_no DESC
4、为了代码良好的可读性,运用了 Alias 别名语句,将 employees 简化为 e,salaries 简化为s,即 employees AS e 与 salaries AS s,其中 AS 可以省略
*/ SELECT e.emp_no,s.salary FROM employees AS e INNER JOIN salaries AS s -- JOIN In 就是JOIN内连接
ON e.emp_no=s.emp_no AND e.hire_date=s.from_date -- 要找到是入职信息
ORDER BY e.emp_no DESC -- 降序排列 # 方法二:直接用逗号并列查询两张表
SELECT e.emp_no, s.salary FROM employees AS e, salaries AS s
WHERE e.emp_no = s.emp_no AND e.hire_date = s.from_date
ORDER BY e.emp_no DESC
5 查找已分配员工姓名
题目描述
查找所有已经分配部门的员工的last_name和first_name
输入描述:
无
输出描述:

直接查询即可:
SELECT e.last_name,e.first_name,d.dept_no
FROM dept_emp AS d, employees AS e
WHERE d.emp_no = e.emp_no
下面是看题目讨论中给出的一些方法,可以参考一下
-- 采用内连接的方式
SELECT e.last_name,e.first_name,d.dept_no FROM dept_emp AS d
INNER JOIN employees AS e
ON e.emp_no = d.emp_no; -- 但此问题只要用自然连接就行了,两张表只有一列相同且属性也相同 SELECT e.last_name, e.first_name, d.dept_no
FROM dept_emp d NATURAL JOIN employees e;
6 查找员工姓名
题目描述
查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工
输入描述:
无
输出描述:

/*
INNER JOIN 两边表同时有对应的数据,即任何一边缺失数据就不显示。
LEFT JOIN 会读取左边数据表的全部数据,即便右边表无对应数据。
RIGHT JOIN 会读取右边数据表的全部数据,即便左边表无对应数据。
*/ SELECT e.last_name, e.first_name, d.dept_no
FROM employees e
LEFT JOIN dept_emp d
ON e.emp_no = d.emp_no
7 查找涨薪找过15次的员工
题目描述
查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t
输入描述:
无
输出描述:

/*
此题应注意以下四点:
1、用COUNT()函数和GROUP BY语句可以统计同一emp_no值的记录条数
2、根据题意,输出的涨幅次数为t,故用AS语句将COUNT(emp_no)的值转换为t
3、由于COUNT()函数不可用于WHERE语句中,故使用HAVING语句来限定t>15的条件
4、最后存在一个理解误区,涨幅超过15次,salaries中相应的记录数应该超过16(从第2条记录开始算作第1次涨幅),不过题目为了简单起见,将第1条记录当作第1次涨幅,所以令t>15即可
注意: 严格来说,下一条salary高于本条才算涨幅,但本题只要出现了一条记录就算一次涨幅,salary相同可以理解为涨幅为0,salary变少理解为涨幅为负
*/
-- group by 可以简单理解为分类汇总
SELECT emp_no, COUNT(emp_no) AS t FROM salaries
GROUP BY emp_no HAVING t > 15
8 找出所有员工当前薪水情况
题目描述
找出所有员工当前(to_date='9999-01-01')具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示
输入描述:
无
输出描述:

/*
对于distinct,groupby的性能。
数据量非常巨大时候,比如1000万中有300W重复数据,这时候的distinct的效率略好于group by;
对于相对重复量较小的数据量比如1000万中1万的重复量,用groupby的性能会远优于distnct
*/ SELECT salary FROM salaries WHERE to_date='9999-01-01' GROUP BY salary ORDER BY salary DESC;
-- 方法二:
SELECT DISTINCT salary FROM salaries WHERE to_date = '9999-01-01' ORDER BY salary DESC
9 获取当前部门所有manager的薪水情况
题目描述
获取所有部门当前manager的当前薪水情况,给出dept_no, emp_no以及salary,当前表示to_date='9999-01-01'
输入描述:
无
输出描述:

自己写的:
SELECT d.dept_no,d.emp_no,s.salary
FROM salaries AS s,dept_manager AS d
WHERE s.to_date='9999-01-01'
AND d.to_date='9999-01-01'
AND d.emp_no = s.emp_no
SELECT d.dept_no, d.emp_no, s.salary
FROM salaries AS s INNER JOIN dept_manager AS d
ON d.emp_no = s.emp_no
AND d.to_date = '9999-01-01' AND s.to_date = '9999-01-01' -- 限制目前时间
-- 下面是讨论中的内容,但我试了下没有order by到也通过了,可能这个本来就不是重要问题吧
-- 将连接语句改成 FROM dept_manager AS d INNER JOIN salaries AS s 后,结果通不过
-- 连接后按照前面的第一个 KEY 值排序,若 salaries 在前,则按照 s.emp_no 排序(因为限制条件为 d.emp_no = s.emp_no,
-- 所以对 s.emp_no 排序就是对d.emp_no 排序),输出跟参考答案一致,没问题;
-- 若 dept_manager 在前,则按照 d.dept_no排序,此时与参考答案不同,所以需要在末尾手动用 ORDER BY 对d.emp_no进行排序。 SELECT d.dept_no, d.emp_no, s.salary
FROM dept_manager AS d INNER JOIN salaries AS s
ON d.emp_no = s.emp_no
AND d.to_date = '9999-01-01'
AND s.to_date = '9999-01-01'
ORDER BY d.emp_no
10 获取所有非manager的员工emp_no
题目描述
获取所有非manager的员工emp_no
输入描述:
无
输出描述:

-- 方法一:使用NOT IN选出在employees但不在dept_manager中的emp_no记录
SELECT emp_no FROM employees
WHERE emp_no NOT IN (SELECT emp_no FROM dept_manager)
-- 方法二:先使用LEFT JOIN连接两张表,再从此表中选出dept_no值为NULL对应的emp_no记录 SELECT emp_no FROM (SELECT * FROM employees LEFT JOIN dept_manager
ON employees.emp_no = dept_manager.emp_no)
WHERE dept_no IS NULL
-- 方法三:方法二的简版,使用单层SELECT语句即可 SELECT employees.emp_no FROM employees LEFT JOIN dept_manager
ON employees.emp_no = dept_manager.emp_no
WHERE dept_no IS NULL -- 方法四:使用集合运算 EXPECT 集合差运算 UNION 集合并运算 INTERSECT 集合交运算
SELECT employees.emp_no
FROM salaries
EXCEPT
SELECT dept_manager.emp_no
FROM dept_manager;
11 获取当前员工的manager
题目描述:
获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date='9999-01-01'。
结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no。
输入描述:
无
输出描述:

/*
本题应注意以下三点:
1、用 INNER JOIN 连接两张表,因为要输出自己的经理,得知自己与经理的部门要相同,故有限制条件 de.dept_no = dm.dept_no
2、再用 WHERE 限制当前员工与当前经理的条件,即 dm.to_date 等于 '9999-01-01' 、de.to_date 等于 '9999-01-01' 、 de.emp_no 不等于 dm.emp_no
3、为了增强代码可读性,将 dept_emp 用别名 de 代替,dept_manager 用 dm 代替,最后根据题意将 de.emp_no 用别名 manager_no 代替后输出
*/
SELECT de.emp_no, dm.emp_no AS manager_no
FROM dept_emp AS de INNER JOIN dept_manager AS dm
ON de.dept_no = dm.dept_no
WHERE dm.to_date = '9999-01-01' AND de.to_date = '9999-01-01' AND de.emp_no <> dm.emp_no
在上面代码中也可以不用使用内联 INNER JOIN的。
12 获取当前薪水最高的员工信息
题目描述
获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary
输入描述:
无
输出描述:

SELECT d.dept_no, s.emp_no, MAX(s.salary) AS salary
FROM salaries AS s INNER JOIN dept_emp AS d
ON d.emp_no = s.emp_no
WHERE d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'
GROUP BY d.dept_no /*
有同学提出疑问,如果存在多条最大记录怎么办?而 MAX 函数根据不同数据库只选择最前一条或最后一条最大记录,其余记录均被忽略。此时解法如下:
1、创建两张表,一张为maxsalary,用于存放当前每个部门薪水的最大值;另一张为currentsalary,用于存放当前每个部门所有员工的编号和薪水;
2、限定条件为两张表的 dept_no 和 salary 相等,这样就可以找出当前每个部门所有薪水等于最大值的员工的相关信息了;
3、最后记得根据 currentsalary.dept_no 升序排列,输出与参考答案相同的记录表。
4、以下代码虽然很长,仔细一看都是基于上面的基础解法变化而来的,中心思想就是绕开 MAX 的特性限制,运用比较的方法选出多个相同的最大值。
*/ SELECT currentsalary.dept_no, currentsalary.emp_no, currentsalary.salary AS salary
FROM
#创建maxsalary表用于存放当前每个部门薪水的最大值
(SELECT d.dept_no, MAX(s.salary) AS salary
FROM salaries AS s INNER JOIN dept_emp AS d
ON d.emp_no = s.emp_no
WHERE d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'
GROUP BY d.dept_no) AS maxsalary,
#创建currentsalary表用于存放当前每个部门所有员工的编号和薪水
(SELECT d.dept_no, s.emp_no, s.salary
FROM salaries AS s INNER JOIN dept_emp AS d
ON d.emp_no = s.emp_no
WHERE d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'
) AS currentsalary
#限定条件为两表的dept_no和salary均相等
WHERE currentsalary.dept_no = maxsalary.dept_no
AND currentsalary.salary = maxsalary.salary
#最后以currentsalary.dept_no排序输出符合要求的记录表
ORDER BY currentsalary.dept_no
0
MySQL基础练习01--牛客网的更多相关文章
- MySql面试题、知识汇总、牛客网SQL专题练习
点击名字直接跳转到链接: Linux运维必会的100道MySql面试题之(一) Linux运维必会的100道MySql面试题之(二) Linux运维必会的100道MySql面试题之(三) Linux运 ...
- 牛客网暑期ACM多校训练营(第三场) A PACM Team 01背包 记录路径
链接:https://www.nowcoder.com/acm/contest/141/A来源:牛客网 Eddy was a contestant participating in ACM ICPC ...
- 牛客网-Beautiful Land 【01背包 + 思维】
链接:https://www.nowcoder.com/acm/contest/119/F来源:牛客网 Now HUST got a big land whose capacity is C to p ...
- Two Graphs 牛客网暑期ACM多校训练营(第一场)D 图论基础知识 全排列
链接:https://www.nowcoder.com/acm/contest/139/D来源:牛客网 Two undirected simple graphs and where are isomo ...
- [牛客网 -leetcode在线编程 -01] max-points-on-a-line -穷举
题目及题目来源 链接:https://www.nowcoder.com/questionTerminal/bfc691e0100441cdb8ec153f32540be2 来源:牛客网 首页 > ...
- 牛客网《BAT面试算法精品课》学习笔记
目录 牛客网<BAT面试算法精品课>学习笔记 牛客网<BAT面试算法精品课>笔记一:排序 牛客网<BAT面试算法精品课>笔记二:字符串 牛客网<BAT面试算法 ...
- 【转自牛客网】C++类职位校招
作者:./a.out链接:https://www.nowcoder.com/discuss/14022来源:牛客网 话说在牛客网上混迹了半年,也没啥拿的出手的贡献.现在基本上自己的校招生涯要告一段落, ...
- 牛客网 Java 工程师能力评估 20 题 - 详解
牛客网 Java 工程师能力评估 20 题 - 详解 不知在看博客的你是否知道 牛客网,不知道就太落后了,分享给你 : 牛客网 此 20 题,绝对不只是 20 题! 免责声明:本博客为学习笔记,如有侵 ...
- 牛客网多校赛第七场--C Bit Compression【位运算】【暴力】
链接:https://www.nowcoder.com/acm/contest/145/C 来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言524 ...
- 牛客网 牛客练习赛43 C.Tachibana Kanade Loves Review-最小生成树(并查集+Kruskal)+建虚点+读入挂
链接:https://ac.nowcoder.com/acm/contest/548/C来源:牛客网 Tachibana Kanade Loves Review 时间限制:C/C++ 2秒,其他语言4 ...
随机推荐
- FastJson 介绍
Json详解 Json是一种轻量级的数据交换格式,采用一种“键:值”对的文本格式来存储和表示数据,在系统交换数据过程中常常被使用,是一种理想的数据交换语言.在使用 Java 做 Web 开发时,不可避 ...
- python — 表的操作(一)
1. 创建表 创建表: create table t1 (id int,name char(4)); create table t2 (id int,name char(4)) engine=myis ...
- 一文看懂java io系统 (转)
出处: 一文看懂java io系统 学习java IO系统,重点是学会IO模型,了解了各种IO模型之后就可以更好的理解java IO Java IO 是一套Java用来读写数据(输入和输出)的A ...
- 第十一章 ZYNQ-MIZ702 DDR3 PS读写操作方案
本编文章的目的主要用简明的方法在纯PS里对DDR3进行读写. 本文所使用的开发板是Miz702 PC 开发环境版本:Vivado 2015.4 Xilinx SDK 2015.4 11.0本章难度 ...
- 并不对劲的CSP-S2019
day1 对题的第一印象: t1:颇有"小凯的疑惑"之风(赛后发现确实如此,因为最好写的正解也可以直接输出) t2:log方会被卡吧?好像倍增一个log?(赛后发现有很好写的线性做 ...
- ORACLE通过JOB定时创建序列
http://blog.csdn.net/cuihaiyang/article/details/7872982 因为业务需要每月需要增加一个序列,想到了使用job定时创建,每次创建一年的.写此job的 ...
- Docker 启动 Mongo
参考:https://hub.docker.com/_/mongo 1,运行这个 docker run --name some-mongo -d mongo 2.进入控制台 docker exec - ...
- sonarqube执行命令遇上的小问题
在安装好sonarqube,本地或是服务器上都是可疑正常运行的情况下. 这一次我重新上传,修改配置SonarQube.Analysis.xml,sonar.host.url的值已经改为服务器上的,执行 ...
- vi学习笔记
dd 删除一行 de删除光标后面的单词 o向下插入一行 O向上插入一行 y复制 yy复制一行 ye复制光标后面的单词 p粘贴 == 代码自动布局 批量注释 ctrl + v , 输入大写I, 选 ...
- oc和swift对代码的分组,方便代码查找和导航用
OC中对代码的分组: 在OC中对代码分组的命令是#pragma mark 来实现的, 分组用的是: #pragma mark 分组名 添加分割线: #pragma mark - 如果想添加分割线的同时 ...