目录

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
输入

输出

  1. -- 查询语句 LIMIT 1 LIMIT 0,1 表是从第0条数据开始取1条数据
  2. SELECT * FROM employees ORDER BY hire_date DESC LIMIT 1;
  3. -- 这个语句有问题在于只找到了一条记录,有可能当天会有好多人入职
  4.  
  5. -- 从表的日期中挑选出最大的就可以避免上述问题了
  6. SELECT * FROM employees WHERE
  7. hire_date=(SELECT MAX(hire_date) FROM employees)

其实对于max也可以用下面的代替:这个和下面查找第三晚的就很类似了

  1. SELECT *
  2. FROM employees
  3. WHERE hire_date=(SELECT hire_date FROM employees ORDER BY hire_date DESC LIMIT 1)

2 查找入职第三晚的员工信息

在上面一个问题的前提下找到第三晚入职的员工

  1. -- distinct 是过滤掉重复的,因为前面的可能日期相同的不止一个,但这样同样会有一个问题
  2. -- 采用下面的方法也是只能挑出来一个信息,当倒数第三个日期有好几个时就会出现错误
  3. SELECT *FROM employees WHERE
  4. hire_date=(SELECT DISTINCT hire_date FROM employees ORDER BY hire_date DESC LIMIT 2,1);

3 查找当前薪水详情及部门编号

题目描述
查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_no
输入描述:

输出描述:

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

上面的代码但在实际开发中是不推荐使用的,因为数据库在使用中应尽量减少物理连接,使用逻辑连接,因此多使用where语句来完成关联,此外使用where在性能上也要比使用join连接快

  1. SELECT s.*,d.dept_no
  2. FROM salaries AS s, dept_manager AS d
  3. WHERE s.emp_no = d.emp_no
  4. AND s.to_date='9999-01-01'
  5. AND d.to_date='9999-01-01'

4 查找所有员工入职时的薪水情况

题目描述
查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序

输入描述:

输出描述:

  1. /*
  2. 此题应注意以下四个知识点:
  3. 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
  4. 2、根据题意注意到 salaries.from_date 和 employees.hire_date 的值应该要相等,因此有限制条件 e.hire_date = s.from_date
  5. 3、根据题意要按照 emp_no 值逆序排列,因此最后要加上 ORDER BY e.emp_no DESC
  6. 4、为了代码良好的可读性,运用了 Alias 别名语句,将 employees 简化为 e,salaries 简化为s,即 employees AS e 与 salaries AS s,其中 AS 可以省略
  7. */
  8.  
  9. SELECT e.emp_no,s.salary FROM employees AS e INNER JOIN salaries AS s -- JOIN In 就是JOIN内连接
  10. ON e.emp_no=s.emp_no AND e.hire_date=s.from_date -- 要找到是入职信息
  11. ORDER BY e.emp_no DESC -- 降序排列
  12.  
  13. # 方法二:直接用逗号并列查询两张表
  14. SELECT e.emp_no, s.salary FROM employees AS e, salaries AS s
  15. WHERE e.emp_no = s.emp_no AND e.hire_date = s.from_date
  16. ORDER BY e.emp_no DESC

5 查找已分配员工姓名

题目描述
查找所有已经分配部门的员工的last_name和first_name
输入描述:

输出描述:

直接查询即可:

  1. SELECT e.last_name,e.first_name,d.dept_no
  2. FROM dept_emp AS d, employees AS e
  3. WHERE d.emp_no = e.emp_no

下面是看题目讨论中给出的一些方法,可以参考一下

  1. -- 采用内连接的方式
  2. SELECT e.last_name,e.first_name,d.dept_no FROM dept_emp AS d
  3. INNER JOIN employees AS e
  4. ON e.emp_no = d.emp_no;
  5.  
  6. -- 但此问题只要用自然连接就行了,两张表只有一列相同且属性也相同
  7.  
  8. SELECT e.last_name, e.first_name, d.dept_no
  9. FROM dept_emp d NATURAL JOIN employees e;

6 查找员工姓名

题目描述
查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工
输入描述:

输出描述:

  1. /*
  2. INNER JOIN 两边表同时有对应的数据,即任何一边缺失数据就不显示。
  3. LEFT JOIN 会读取左边数据表的全部数据,即便右边表无对应数据。
  4. RIGHT JOIN 会读取右边数据表的全部数据,即便左边表无对应数据。
  5. */
  6.  
  7. SELECT e.last_name, e.first_name, d.dept_no
  8. FROM employees e
  9. LEFT JOIN dept_emp d
  10. ON e.emp_no = d.emp_no

7 查找涨薪找过15次的员工

题目描述
查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t
输入描述:

输出描述:

  1. /*
  2. 此题应注意以下四点:
  3. 1、用COUNT()函数和GROUP BY语句可以统计同一emp_no值的记录条数
  4. 2、根据题意,输出的涨幅次数为t,故用AS语句将COUNT(emp_no)的值转换为t
  5. 3、由于COUNT()函数不可用于WHERE语句中,故使用HAVING语句来限定t>15的条件
  6. 4、最后存在一个理解误区,涨幅超过15次,salaries中相应的记录数应该超过16(从第2条记录开始算作第1次涨幅),不过题目为了简单起见,将第1条记录当作第1次涨幅,所以令t>15即可
  7. 注意: 严格来说,下一条salary高于本条才算涨幅,但本题只要出现了一条记录就算一次涨幅,salary相同可以理解为涨幅为0,salary变少理解为涨幅为负
  8. */
  9. -- group by 可以简单理解为分类汇总
  10. SELECT emp_no, COUNT(emp_no) AS t FROM salaries
  11. GROUP BY emp_no HAVING t > 15

8 找出所有员工当前薪水情况

题目描述
找出所有员工当前(to_date='9999-01-01')具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示
输入描述:

输出描述:

  1. /*
  2. 对于distinct,groupby的性能。
  3. 数据量非常巨大时候,比如1000万中有300W重复数据,这时候的distinct的效率略好于group by;
  4. 对于相对重复量较小的数据量比如1000万中1万的重复量,用groupby的性能会远优于distnct
  5. */
  6.  
  7. SELECT salary FROM salaries WHERE to_date='9999-01-01' GROUP BY salary ORDER BY salary DESC;
  8. -- 方法二:
  9. 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'
输入描述:

输出描述:

自己写的:

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

10 获取所有非manager的员工emp_no

题目描述
获取所有非manager的员工emp_no
输入描述:

输出描述:

  1. -- 方法一:使用NOT IN选出在employees但不在dept_manager中的emp_no记录
  2. SELECT emp_no FROM employees
  3. WHERE emp_no NOT IN (SELECT emp_no FROM dept_manager)
  4. -- 方法二:先使用LEFT JOIN连接两张表,再从此表中选出dept_no值为NULL对应的emp_no记录
  5.  
  6. SELECT emp_no FROM (SELECT * FROM employees LEFT JOIN dept_manager
  7. ON employees.emp_no = dept_manager.emp_no)
  8. WHERE dept_no IS NULL
  9. -- 方法三:方法二的简版,使用单层SELECT语句即可
  10.  
  11. SELECT employees.emp_no FROM employees LEFT JOIN dept_manager
  12. ON employees.emp_no = dept_manager.emp_no
  13. WHERE dept_no IS NULL
  14.  
  15. -- 方法四:使用集合运算 EXPECT 集合差运算 UNION 集合并运算 INTERSECT 集合交运算
  16. SELECT employees.emp_no
  17. FROM salaries
  18. EXCEPT
  19. SELECT dept_manager.emp_no
  20. FROM dept_manager;

11 获取当前员工的manager

题目描述:
获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date='9999-01-01'。
结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no。
输入描述:

输出描述:

  1. /*
  2. 本题应注意以下三点:
  3. 1、用 INNER JOIN 连接两张表,因为要输出自己的经理,得知自己与经理的部门要相同,故有限制条件 de.dept_no = dm.dept_no
  4. 2、再用 WHERE 限制当前员工与当前经理的条件,即 dm.to_date 等于 '9999-01-01' 、de.to_date 等于 '9999-01-01' 、 de.emp_no 不等于 dm.emp_no
  5. 3、为了增强代码可读性,将 dept_emp 用别名 de 代替,dept_manager 用 dm 代替,最后根据题意将 de.emp_no 用别名 manager_no 代替后输出
  6. */
  7. SELECT de.emp_no, dm.emp_no AS manager_no
  8. FROM dept_emp AS de INNER JOIN dept_manager AS dm
  9. ON de.dept_no = dm.dept_no
  10. 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
输入描述:

输出描述:

  1. SELECT d.dept_no, s.emp_no, MAX(s.salary) AS salary
  2. FROM salaries AS s INNER JOIN dept_emp AS d
  3. ON d.emp_no = s.emp_no
  4. WHERE d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'
  5. GROUP BY d.dept_no
  6.  
  7. /*
  8. 有同学提出疑问,如果存在多条最大记录怎么办?而 MAX 函数根据不同数据库只选择最前一条或最后一条最大记录,其余记录均被忽略。此时解法如下:
  9. 1、创建两张表,一张为maxsalary,用于存放当前每个部门薪水的最大值;另一张为currentsalary,用于存放当前每个部门所有员工的编号和薪水;
  10. 2、限定条件为两张表的 dept_no 和 salary 相等,这样就可以找出当前每个部门所有薪水等于最大值的员工的相关信息了;
  11. 3、最后记得根据 currentsalary.dept_no 升序排列,输出与参考答案相同的记录表。
  12. 4、以下代码虽然很长,仔细一看都是基于上面的基础解法变化而来的,中心思想就是绕开 MAX 的特性限制,运用比较的方法选出多个相同的最大值。
  13. */
  14.  
  15. SELECT currentsalary.dept_no, currentsalary.emp_no, currentsalary.salary AS salary
  16. FROM
  17. #创建maxsalary表用于存放当前每个部门薪水的最大值
  18. (SELECT d.dept_no, MAX(s.salary) AS salary
  19. FROM salaries AS s INNER JOIN dept_emp AS d
  20. ON d.emp_no = s.emp_no
  21. WHERE d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'
  22. GROUP BY d.dept_no) AS maxsalary,
  23. #创建currentsalary表用于存放当前每个部门所有员工的编号和薪水
  24. (SELECT d.dept_no, s.emp_no, s.salary
  25. FROM salaries AS s INNER JOIN dept_emp AS d
  26. ON d.emp_no = s.emp_no
  27. WHERE d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'
  28. ) AS currentsalary
  29. #限定条件为两表的dept_no和salary均相等
  30. WHERE currentsalary.dept_no = maxsalary.dept_no
  31. AND currentsalary.salary = maxsalary.salary
  32. #最后以currentsalary.dept_no排序输出符合要求的记录表
  33. ORDER BY currentsalary.dept_no

0

MySQL基础练习01--牛客网的更多相关文章

  1. MySql面试题、知识汇总、牛客网SQL专题练习

    点击名字直接跳转到链接: Linux运维必会的100道MySql面试题之(一) Linux运维必会的100道MySql面试题之(二) Linux运维必会的100道MySql面试题之(三) Linux运 ...

  2. 牛客网暑期ACM多校训练营(第三场) A PACM Team 01背包 记录路径

    链接:https://www.nowcoder.com/acm/contest/141/A来源:牛客网 Eddy was a contestant participating in ACM ICPC ...

  3. 牛客网-Beautiful Land 【01背包 + 思维】

    链接:https://www.nowcoder.com/acm/contest/119/F来源:牛客网 Now HUST got a big land whose capacity is C to p ...

  4. Two Graphs 牛客网暑期ACM多校训练营(第一场)D 图论基础知识 全排列

    链接:https://www.nowcoder.com/acm/contest/139/D来源:牛客网 Two undirected simple graphs and where are isomo ...

  5. [牛客网 -leetcode在线编程 -01] max-points-on-a-line -穷举

    题目及题目来源 链接:https://www.nowcoder.com/questionTerminal/bfc691e0100441cdb8ec153f32540be2 来源:牛客网 首页 > ...

  6. 牛客网《BAT面试算法精品课》学习笔记

    目录 牛客网<BAT面试算法精品课>学习笔记 牛客网<BAT面试算法精品课>笔记一:排序 牛客网<BAT面试算法精品课>笔记二:字符串 牛客网<BAT面试算法 ...

  7. 【转自牛客网】C++类职位校招

    作者:./a.out链接:https://www.nowcoder.com/discuss/14022来源:牛客网 话说在牛客网上混迹了半年,也没啥拿的出手的贡献.现在基本上自己的校招生涯要告一段落, ...

  8. 牛客网 Java 工程师能力评估 20 题 - 详解

    牛客网 Java 工程师能力评估 20 题 - 详解 不知在看博客的你是否知道 牛客网,不知道就太落后了,分享给你 : 牛客网 此 20 题,绝对不只是 20 题! 免责声明:本博客为学习笔记,如有侵 ...

  9. 牛客网多校赛第七场--C Bit Compression【位运算】【暴力】

    链接:https://www.nowcoder.com/acm/contest/145/C 来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言524 ...

  10. 牛客网 牛客练习赛43 C.Tachibana Kanade Loves Review-最小生成树(并查集+Kruskal)+建虚点+读入挂

    链接:https://ac.nowcoder.com/acm/contest/548/C来源:牛客网 Tachibana Kanade Loves Review 时间限制:C/C++ 2秒,其他语言4 ...

随机推荐

  1. JDBC 资源绑定器 ,处理查询结果集

    使用资源绑定器绑定属性配置 实际开发中不建议把连接数据库的信息写死到Java程序中 //使用资源绑定器绑定属性配置 ResourceBundle bundle = ResourceBundle.get ...

  2. vscode+php+xdebug won't stop at breakpoint 断点不起作用

    not stopping on breakpoints breakpoint not working 原因: 1) php.ini xdebug 端口不配置的情况下,默认是 9000,如果vscode ...

  3. JMM(Java内存模型)是什么?为什么使用并发?

    1.计算机 首先我们需要讲解下计算机的模型:现代计算机模型是基于-冯诺依曼计算机模型 我们不用管输入和输出设备,最主要的就是中间计算器和存储器之间的交互,也就是CPU与主内存之间取数.存数. 大家会看 ...

  4. Idea加载项目扫描完毕后自动退出

    问题描述:Idea平时好好的,突然就打开后扫描完毕后自动退出.网上说修改idea.exe.vmoptions文件的Xmx,还是不行. 后来根据http://www.pianshen.com/artic ...

  5. C# 将一种类型的数组转化为另一种类型的数组

    //字符串数组(源数组) "}; //整型数组(目标数组) int[] iNums; //转换方法 iNums = Array.ConvertAll<string, int>(s ...

  6. C++ STL 之 list

    #include <list> #include <iostream> using namespace std; // 打印list元素 void PrintList(list ...

  7. C#面向对象(五大基本原则 )

    五大原则 单一职责原则(SRP)开放封闭原则(OCP) 里氏替换原则(LSP) 依赖倒置原则(DIP) 接口隔离原则(ISP)  一.单一职责原则SRP(Single Responsibility P ...

  8. linux 使用 rz 上传和 sz下载 命令

    linux系统 root权限 lrzsz安装包 ①.在线安装-执行命令 yum install lrzsz  离线安装-需要提前准备好安装包 编译安装 root 账号登陆后,依次执行以下命令: tar ...

  9. day_03比特币转账的运行原理

    在2008年全球经济危机中,中本聪想如果能构建一个没有中心机构的货币发行体系,货币就不会被无限发行,大家都很公平公正,于是中本聪构建了比特币这样一个体系: 一.非中心化下的比特币发行机制 比特币的发行 ...

  10. 基于C++11的100行实现简单线程池

    基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...