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

输出

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也可以用下面的代替:这个和下面查找第三晚的就很类似了

SELECT *
FROM employees 
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_manager的dept_no列
 3 FROM salaries AS s JOIN dept_manager AS d -- 两个as相当于对表重命名,所以一开始才可以直接用s和d表示两个表
 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 -- 执行顺序为先 on再where
 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连接快

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 /*
 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
输入描述:

输出描述:

直接查询即可:

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

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

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'
输入描述:

输出描述:

自己写的:

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

原文地址:https://www.cnblogs.com/youngao/p/9799212.html