数据库查询语句实例

 

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

select * from employees where hire_date = (select max(hire_date) from employees)

           运行时间:21ms         占用内存:3424k

查询语句2

select * from employees order by hire_date desc limit 1;

          运行时间:22ms          占用内存:3432k

讨论:在运行时间及内存占用上两者差别不大,但需要注意的是如果hire_date的格式是2015-12-14这种,不排除当天入职的人不止一个的情况,因此,语句1会将当天入职的人都找出来,而语句二只会找出你指定的数量。

2. 查找入职员工时间排名倒数第三的员工所有信息

还是上面的员工表,写出查询语句:

select * from employees order by hire_date desc limit 2,1;

      运行时间:19ms      占用内存:3320k

select * from employees
where hire_date=(select distinct hire_date from employees order by hire_date desc limit 2,1);

     运行时间:23ms     占用内存:3552k

讨论:两条语句考虑的点有些许差别,前一条语句直接考虑可能有重复的情况,哪怕当天有多人入职也一并进行排序取倒数第三个;后一条语句则先对同日期入职的数据进行去重然后再排序取倒数第三个;

3. 查找各个部门当前(to_date='9999-01-01')领导当前薪水详情以及其对应部门编号dept_no

表格结构为:

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
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`));

查询语句:

SELECT s.*, d.dept_no FROM salaries s ,  dept_manager d
WHERE s.to_date='9999-01-01' 
AND d.to_date='9999-01-01' 
AND s.emp_no = d.emp_no;

     运行时间:18ms     占用内存:3552k

select s.* ,d.dept_no
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';

       运行时间:21ms      占用内存:3424k

讨论:两条语句查询的本质是一样的,只不过后一条用的是join关联两表,而前一条语句则是通过条件外键关联;注意一点小问题,因为查询语句中s表在前,d表在后,因而查询所得的结果也是这个顺序。

4. 查找所有已经分配部门的员工的last_name和first_name及其部门编号

数据表格为:

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

查询语句:

SELECT e.last_name, e.first_name, d.dept_no
FROM employees e, dept_emp d where d.emp_no = e.emp_no and dept_no is not null;

5. 查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工

         表结构与上一题一样,但与上一题的 区别在于这里要找到所有员工的相关信息;因此说明员工表的所有员工信息都需要找到,左连接可以保证左表的信息都得以保留;

查询语句:

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;

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

表结构:

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

思路:

此题应注意以下四个知识点:

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 可以省略

查询语句:

方法一:利用 INNER JOIN 连接两张表
SELECT e.emp_no, s.salary FROM employees AS e INNER JOIN salaries AS s
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

7. 查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t

表结构:

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

思路:
此题应注意以下四点:

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变少理解为涨幅为负 **/

SELECT emp_no, COUNT(emp_no) AS t FROM salaries 
GROUP BY emp_no HAVING t > 15;

注意where和having的区别:

WHERE语句在GROUP BY语句之前;SQL会在分组之前计算WHERE语句。   

HAVING语句在GROUP BY语句之后;SQL会在分组之后计算HAVING语句。

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

表结构与上题一致

方式一:
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;

对于distinct,groupby的性能解释:

  1. 数据量非常巨大时候,比如1000万中有300W非重复数据,这时候的distinct的效率略好于group by;
  2. 对于相对重复量较小的数据量比如1000万中1万非重复数据,用groupby的性能会远优于distnct。

简单点说就是重复的数据越多用groupby来分组统计性能更好。

9. 获取所有部门当前manager的当前薪水情况,给出dept_no, emp_no以及salary,当前表示to_date='9999-01-01'

表结构如下:

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
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`));

查询语句:

方式一:自然的使用条件where
select d.dept_no,d.emp_no,s.salary from dept_manager as d,salaries as s
where d.emp_no = s.emp_no and s.to_date='9999-01-01' and d.to_date='9999-01-01'
order by d.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';

相关思路:

1、先用INNER JOIN连接两张表,限制条件是两张表的emp_no相同,即d.emp_no = s.emp_no,并且将salaries用别名s代替,dept_manager用别名d代替;

2、根据题意,要获取当前manager的当前salary情况,再加上限制条件d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'即可(因为同一emp_no在salaries表中对应多条涨薪记录,而当s.to_date = '9999-01-01'时是该员工当前的薪水记录);

3、使用表连接时由于题目没有特别要求,因此内连接简便,如若题目要求当前部门经理有工资的话,就显示出来,没有的话,salary就置为空的话,那么就需要使用左连接或右连接。

10、获取所有非manager的员工emp_no

表结构:

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
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`));
方法一:使用NOT IN选出在employees但不在dept_manager中的emp_no记录
1SELECT 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

注意:

         MySQL官方文档有说明,in关键字适合确定数量的情况,一般效率较低,不推荐使用。能用in关键字的语句都可以转化为使用join的语句,推荐使用join关键字。

11、获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date='9999-01-01'。结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_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 `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_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;

注意:

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 代替后输出。

持续更新。。。

猜你喜欢

转载自blog.csdn.net/Coding___Man/article/details/84400978