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 ...
随机推荐
- Java:泛型的理解
本文源自参考<Think in Java>,多篇博文以及阅读源码的总结 前言 Java中的泛型每各人都在使用,但是它底层的实现方法是什么呢,为何要这样实现,这样实现的优缺点有哪些,怎么解决 ...
- ubuntu 忘记密码如何 修改密码
ubuntu 忘记密码如何 修改密码 这个链接讲的很不错 https://blog.csdn.net/zd147896325/article/details/81664558 本来我只是玩一玩,但是我 ...
- 小木棒HDU1455(DFS+剪枝)
题意:HDU1455 给出n个小木棒的长度,他们是又数根长度相同的木棒剪短得来的,问没剪短之前的木棒长度最短是多少. 思路: 见代码:https://www.cnblogs.com/fqfzs/p/9 ...
- thinkphp5中的raw的作用
模板中输出变量 默认不展示HTMl 使用raw将其中的中的HTMl内容展示出来 <div class="content"> <div class="co ...
- Unable to find optional library: org.apache.http.legacy 错误
在目录adt-bundle-windows-x86_64-20140702\sdk\platforms\android-20或者 C:\Users\Administrator\AppData\Loca ...
- linux 安装telnet
一.CentOS下查看系统是否已安装telnet rpm -qa | grep telnet telnet 是挂在 xinetd 底下的,所以同时查看是否安装了xinetd服务 rpm -qa | g ...
- Class.getResources()和classLoader.getResources()区别
Class.getResource(String path) path不以’/'开头时,默认是从此类所在的包下取资源: path 以’/'开头时,则是从ClassPath根下获取: package t ...
- MySQL SELECT语法(二)SELECT...INTO语法
源自MySQL 5.7 官方手册 SELECT...INTO Syntax 一.SELECT...INTO介绍 SELECT...INTO用来将查询结果存储在变量或者写入文件中. SELECT ... ...
- 搭建Leanote网络云笔记
下载启动 MongoDB Leanote 依赖 MongoDB 作为数据存储,下面开始安装 MongoDB: 下载 MongoDB 进入 /home 目录,并下载 MongoDB: cd /home ...
- 怎样快捷获取网页的window对象
使用document.defaultView; document.defaultView === window 注意: 1. 如果当前文档不属于window对象, 则返回null; 2. docume ...