常用sql语句总结1

来源于:牛客网
  

1.sql查找表中多余的重复记录,重复记录是根据单个字段(itemId)来判断:

答:

1
2
3
select * from tb_Item
where itemId in (select itemId from tb_Item
group by itemId having count(itemId) > 1 )

  

2.1 查找最晚入职员工的所有信息:

1
2
3
4
5
6
7
8
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
2
3
select * from employees
where hire_date =
(select max(hire_date) from employees)

  

2.2 查找入职员工时间排名倒数第三的员工所有信息(接上题)

答:对入职时间进行降序排列,从第2条记录开始,选取1条记录信息。

1
SELECT * FROM employees ORDER BY hire_date DESC LIMIT 2,1

  

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

1
2
3
4
5
6
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`));
1
2
3
4
5
6
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:

1
2
3
4
5
select s.*, d.dept_no
from salaries s, dept_manager d
where s.emp_no = d.emp_no
and s.to_date = '9999-01-01'
and d.to_date = '9999-01-01'

解2:(使用关联查询)

1
2
3
4
5
6
select s.*, d.dept_no
from salaries as s
inner join dept_manager as d
on s.emp_no = d.emp_no
and s.to_date = '9999-01-01'
and d.to_date = '9999-01-01'

解3:(只是加了一个where)

1
2
3
4
5
6
select s.*, d.dept_no
from salaries s
inner join dept_manager d
on s.emp_no = d.emp_no
where s.to_date = '9999-01-01'
and d.to_date = '9999-01-01'

  

4.1 查找所有已经分配部门的员工的last_name和first_name

1
2
3
4
5
6
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`));
1
2
3
4
5
6
7
8
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
2
3
4
select e.last_name, e.first_name, d.dept_no
from employees e
inner join dept_emp d
on e.emp_no = d.emp_no

解2:(//只有一列是公有的,用自然连接)

1
2
3
select e.last_name, e.first_name, d.dept_no
from employees e
natural join dept_emp d

  

4.2 查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工(接上题)

答:

1
2
3
4
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

注意:

  • INNER JOIN 两边表同时有对应的数据,即任何一边缺失数据就不显示。

  • LEFT JOIN 会读取左边数据表的全部数据,即便右边表无对应数据。

  • RIGHT JOIN 会读取右边数据表的全部数据,即便左边表无对应数据。

4.3查找所有员工入职时候的薪水情况,给出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 可以省略

方法一:利用 INNER JOIN 连接两张表

1
2
3
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

方法二:直接用逗号并列查询两张表

1
2
3
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.查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t:

1
2
3
4
5
6
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
2
3
SELECT emp_no, COUNT(emp_no) AS t 
FROM salaries
GROUP BY emp_no HAVING t > 15

解析:
此题应注意以下四点:
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变少理解为涨幅为负   

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

答:
方式一:

1
2
3
SELECT DISTINCT salary FROM salaries 
WHERE to_date='9999-01-01'
ORDER BY salary DESC;

方式二:

1
2
3
4
SELECT salary FROM salaries 
WHERE to_date='9999-01-01'
GROUP BY salary
ORDER BY salary DESC;

解析:
对于distinct,groupby的性能:
1.数据量非常巨大时候,比如1000万中有300W重复数据,这时候的distinct的效率略好于group by;
2.对于相对重复量较小的数据量比如1000万中1万的重复量,用groupby的性能会远优于distnct;
3.简书上的一篇博客说的不错,大家可以穿送过去看一看传送门

  

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

1
2
3
4
5
6
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`));
1
2
3
4
5
6
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关联查询语句)

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

方式二:(内连接)

1
2
3
4
5
6
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
WHERE d.to_date = '9999-01-01'
AND s.to_date = '9999-01-01'

或:

1
2
3
4
5
6
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'

  

8.获取所有非manager的员工emp_no:

1
2
3
4
5
6
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`));
1
2
3
4
5
6
7
8
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记录)

1
2
SELECT emp_no FROM employees
WHERE emp_no NOT IN (SELECT emp_no FROM dept_manager)

方式二:(先使用LEFT JOIN连接两张表,再从此表中选出dept_no值为NULL对应的emp_no记录)

1
2
3
4
SELECT e.emp_no FROM employees e 
LEFT JOIN dept_manager d
ON e.emp_no = d.emp_no
WHERE dept_no IS NULL

  

9.获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date=’9999-01-01’。结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no。

1
2
3
4
5
6
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`));
1
2
3
4
5
6
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`));

答:
方式一:(使用where条件语句)

1
2
3
4
5
6
SELECT de.emp_no, dm.emp_no AS manager_no
FROM dept_manager AS dm, dept_emp AS de
WHERE de.dept_no = dm.dept_no
AND de.to_date='9999-01-01'
AND dm.to_date='9999-01-01'
AND de.emp_no <> dm.emp_no

方式二:(使用inner join内连接)

1
2
3
4
5
6
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 代替后输出   

10.获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary:

1
2
3
4
5
6
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`));
1
2
3
4
5
6
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
2
3
4
5
6
SELECT de.dept_no, de.emp_no, max(s.salary) salary 
FROM dept_emp de,salaries s
WHERE de.emp_no = s.emp_no
AND de.to_date = '9999-01-01'
AND s.to_date = '9999-01-01'
GROUP BY de.dept_no;

方式二:

1
2
3
4
5
6
7
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

---------------- The End ----------------
0%