首先了解下sql语句底层执行顺序:

select 5
from 1
where 2
group by 3
having 4
order by 6

下面开始进行一些MySQL试题训练,这些题目都是网上找到的,不过那个版本使用Oracle数据库写的答案,学数据库的应该都知道,MySQL与Oracle的语句还是有些差别的。以下是我自己根据环境和题目写的。 环境的话自己可以搭建一个,数据库表我贴出来了仅供使用,内容如下:

/*
SQLyog Ultimate v11.22 (64 bit)
MySQL - 5.0.67-community 
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;

#复制此文件内所有内容执行,创建Company数据库和数据。

CREATE DATABASE company;

Use company;

create table `dept` (
	`deptno` int (2),
	`dname` varchar (60),
	`loc` varchar (60),
	primary key(deptno),
	index dept_index(deptno)
)ENGINE=INNODB DEFAULT CHARSET=utf8; 
insert into `dept` (`deptno`, `dname`, `loc`) values('10','ACCOUNTING','NEW YORK');
insert into `dept` (`deptno`, `dname`, `loc`) values('20','RESEARCH','DALLAS');
insert into `dept` (`deptno`, `dname`, `loc`) values('30','SALES','CHICAGO');
insert into `dept` (`deptno`, `dname`, `loc`) values('40','OPERATIONS','BOSTON');

CREATE TABLE `emp` (
	`empno` INT (4) primary key,
	`ename` VARCHAR (60),
	`job` VARCHAR (30),
	`mgr` INT (4),
	`hiredate` DATE ,
	`sal` FLOAT ,
	`comm` FLOAT ,
	`deptno` INT (2),
	index emp_index(deptno),
	foreign key(deptno) references dept(deptno) on delete cascade on update cascade 
)ENGINE=INNODB DEFAULT CHARSET=utf8; 
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7369','SMITH','CLERK','7902','1980-12-17','800.00',NULL,'20');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7499','ALLEN','SALESMAN','7698','1981-02-20','1600.00','300.00','30');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7521','FORD','SALESMAN','7698','1981-02-22','1250.00','500.00','20');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7566','JONES','MANAGER','7839','1981-04-02','2975.00',NULL,'20');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7654','MARTIN','SALESMAN','7698','1981-09-28','1250.00','1400.00','30');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7698','BLAKE','MANAGER','7839','1981-05-01','2850.00',NULL,'30');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7782','CLARK','MANAGER','7839','1981-06-09','2450.00',NULL,'10');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7788','SCOTT','ANALYST','7566','1987-04-19','3000.00',NULL,'20');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7839','KING','PRESIDENT',NULL,'1981-11-17','5000.00',NULL,'10');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7844','TURNER','SALESMAN','7698','1981-09-08','1500.00','0.00','30');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7876','ADAMS','CLERK','7788','1987-05-23','2200.00',NULL,'20');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7900','JAMES','CLERK','7698','1981-12-03','950.00',NULL,'30');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7902','FORD','ANALYST','7566','1981-12-03','3000.00',NULL,'20');
INSERT INTO `emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES('7934','MILLER','CLERK','7782','1982-01-23','1300.00',NULL,'10');

create table `salgrade` (
	`grade` int (1) primary key,
	`losal` float ,
	`hisal` float 
); 
insert into `salgrade` (`grade`, `losal`, `hisal`) values('1','700.00','1200.00');
insert into `salgrade` (`grade`, `losal`, `hisal`) values('2','1201.00','1400.00');
insert into `salgrade` (`grade`, `losal`, `hisal`) values('3','1401.00','2000.00');
insert into `salgrade` (`grade`, `losal`, `hisal`) values('4','2001.00','3000.00');
insert into `salgrade` (`grade`, `losal`, `hisal`) values('5','3001.00','9999.00');

废话不多说,开练吧! -- 1.查询emp表,显示薪水大于2000,且工作类别是MANAGER的雇员信息

select * 
from emp 
where sal > 2000 
and job = 'MANAGER';

-- 2.查询emp表,显示年薪大于30000,工作类别不是MANAGER的雇员信息

select * 
from emp
where job <> 'MANAGER'
and sal*12+ifnull(comm,0) > 30000;
/*ifnull(值1,值2) 当值1非空,显示它本身的值即值1,当值1为空null,显示值2的值.所以这里的意思是当comm的值为空时,显示值2也就是0

-- 3.查询emp表, 显示薪水在1500到3000之间,工作类别以“M”开头的雇员信息

select *
from emp
where sal between 1500 and 3000
and job like 'M%';
/* like是模糊查询,%匹配任意字符,只要开头是M的字符都在统计范围。 如果是'M_',那就是匹配已M开头的两个字符长度的数值

-- 4.查询emp表,显示佣金为空并且部门号为20或30的雇员信息

select * 
from emp
where comm is null
and deptno in (20,30);
/*in,是在什么内

-- 5.查询emp表,显示佣金不为空或者部门号为20的雇员信息,要求按照薪水降序排列

select * 
from emp
where comm is not null
and deptno=20
order by sal desc;
/*不等于也可以用<>,!=

-- 6.查询emp表,显示年薪大于30000工作类别不是MANAGER,且部门号不是10或40的雇员信息,要求按照雇员姓名进行排列

select * 
from emp
where 12*sal+ifnull(comm,0)>30000
and job <>'MANAGER'
and deptno not in (10,40)
order by ename ;
/*order by 是排序,由于默认是升序,所以asc可加或不加,desc是倒序。 order by string asc/desc,两个字段以上可用逗号分隔

-- 7.查询EMP、DEPT表,输出的列包含员工姓名、工资、部门编号、部门名称、部门地址.

select ename,sal,a.deptno,dname,loc
from emp a,dept b
where a.deptno=b.deptno;
/*a和b的作用类似于别名,这样可以区分不同表之间相同的列名。

-- 8.使用自连接查询EMP表,输出的列包含员工姓名、主管姓名.

select boss.ename 老板,works.ename 员工
from emp boss,emp works
where boss.mgr=works.empno;

-- 9.在上一题的基础上,思考下为什么输出结果没有KING的信息? 如果要输出KING的信息,如何修改?

select boss.ename 老板,works.ename 员工
from emp boss left join emp works
on boss.mgr=works.empno;
/*emp boss与emp works交换位置的话,就可以用右链接right join ... on

-- 10.使用左连接查询员工部门,包括没有员工的部门信息,输出列:部门编号、部门名称、位置。 --(左表为dept表,emp为右表)

select a.deptno,dname,loc
from dept a left join emp b
on a.deptno=b.deptno;

-- 11.查询EMP表,输出每个部门的平均工资,并按部门编号降序排列.

select deptno,avg(sal)
from emp
group by deptno
ORDER BY deptno desc;

-- 12.查询EMP表,输出每个职位的平均工资,按平均工资升序排列.

select job,avg(sal) as sal_avg
from emp
group by job
order by sal_avg;
/*as后面跟的是别名,这样order by后面也可以根别名来排序

-- 13.查询EMP表,输出每个部门的各个职位的平均工资,并按部门编号升序、平均工资降序排序。

select deptno,job,avg(sal) 
from emp 
group by deptno,job
order by deptno,avg(sal) desc;

-- 14.使用子查询,找出哪个部门下没有员工

方法1:
select * from dept where deptno <> all (select deptno from emp);
方法2:
select * from dept where deptno not in (select deptno from emp);

-- 15.使用子查询,找出那些工资低于所有部门的平均工资的员工

select * 
from emp 
where sal < all (select avg(sal) from emp GROUP BY deptno);
/*当子查询返回多个结果时,只能用in/any/all。 any是任意,all是全部

-- 16.使用子查询,找出那些工资低于任意部门的平均工资的员工,比较一下与上一题输出的结果是否相同?

select * 
from emp 
where sal < any (select avg(sal) from emp GROUP BY deptno);

-- 17.在EMP表中,增加一名员工,员工信息参照现有员工构造.

insert into 
emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) 
values(8999,'zhang','manager',null,now(),7000,2000,10);
/*如果是全表插入,那表结构可不写,直接写值values就行

-- 18.员工SMITH部门调动到SALES部门,请编写SQL语句更新员工信息.

update  emp 
set deptno= (select deptno from dept where dname='SALES') 
where ename='SMITH';
/*这里要注意,MySQL不能删除或更新与子查询一样的表,否则会报错。也就是子查询中的表不能与修改的表相同。Oracle没这个限制。但是MySQL遇到这种情况时只要在套一层即可,具体方法最后后面会有题目遇到。

-- 19.员工JAMES已经离职,请编写SQL语句更新数据库.

delete from emp 
where ename='james';

-- 20.用户执行delete from emp;语句删除了EMP表的记录,但没有提交,请问有办法恢复EMP原来的数据吗? 答: navicat工具是直接删除了,最好别操作。每次更新或删除操作前切记都进行备份。

-- 21.得到平均工资大于2000的工作职种

select job,avg(sal)
from emp 
group by job
having avg(sal) > 2000;

-- 22.分部门得到工资大于2000的所有员工的平均工资,并且平均工资还要大于2500

select deptno,avg(sal)
from emp 
where sal>2000
group by deptno
having avg(sal)>2500;

-- 23.得到每个月工资总数最少的那个部门的部门编号,部门名称,部门位置

select a.deptno,b.dname,b.loc,sum(sal) 
from emp a, dept b
where a.deptno=b.deptno
group by a.deptno,b.dname
order by sum(sal)  limit 1;  /*排序取一行

-- 24.分部门得到平均工资等级为2级(等级表)的部门编号

select deptno,grade,avg(sal)
from emp,salgrade
where sal between losal and hisal
and grade=2;
group by deptno

-- 25.查找出部门10和部门20中,工资最高第3名到工资第5名的员工的员工名字,部门名字,部门位置

select a.deptno,ename,dname,loc,sal
from emp a,dept b
where a.deptno=b.deptno
and a.deptno in (10,20)  order by sal desc limit 2,3; 
/*limit 数值1,数值2
数值1:0 代表从第一行开始取值
       1 代表从第二行开始取值
数值2:代表取多少行记录*/

-- 26.查找出收入(工资加上奖金),下级比自己上级还高的员工编号,员工名字,员工收入

select a.ename,a.empno,a.sal
from emp a,emp aa
where a.mgr=aa.empno
and a.sal+ifnull(a.comm,0)>aa.sal+IFNULL(aa.comm,0);

-- 27.查找出职位和'MARTIN' 或者'SMITH'一样的员工的平均工资 */

select job,avg(sal) 
from emp 
where job in (select job from emp where ename in ('MARTIN','SMITH')) 
GROUP BY job;

-- 28.查找出不属于任何部门的员工

select * 
from dept 
where deptno not in (select deptno from emp);

-- 29.按部门统计员工数,查出员工数最多的部门的第二名到第五名(列出部门名字,部门位置)

select a.deptno,count(ename),b.loc
from  emp a, dept b
where a.deptno=b.deptno
GROUP BY deptno
order by count(ename) desc limit 1,4;

-- 30.查询出king所在部门的部门号\部门名称\部门人数

select count(1),dname,a.deptno 
from emp a,dept b 
where  a.deptno=b.deptno  
and a.deptno = (select deptno from emp where ename='king');

-- 31.查询出king所在部门的工作年限最大的员工名字

select hiredate,ename 
from emp 
where deptno =(select deptno from emp where ename='king')  
ORDER BY hiredate  limit 1;

-- 32.查询出工资成本最高的部门的部门号和部门名称

select a.deptno,dname,sum(sal)
from emp a , dept b
where a.deptno=b.deptno
group by deptno
ORDER BY sum(sal) desc limit 1;

-- 33.显示所有员工的姓名、工作和薪金,按工作的降序排序,若工作相同则按薪金排序.

select ename,job,sal
from emp
order by job desc,sal;

-- 34.显示所有员工的姓名、加入公司的年份和月份,按受雇日期所在月排序,若月份相同则将最早年份的员工排在最前面.

select ename,DATE_FORMAT(hiredate,'%Y') years,date_format(hiredate,'%m') months
from emp 
ORDER BY months,years;

-- 35.显示在一个月为30天的情况所有员工的日薪金,忽略余数

select *,sal*12/360 sal_day 
from emp;

-- 36.找出在(任何年份的)2月受聘的所有员工。

select * 
from emp 
where date_format(hiredate,'%m')=2;

-- 37.对于每个员工,显示其加入公司的天数.

select ename,hiredate,date(now()) 当前日期,DATEDIFF(now(),hiredate) 入职天数 
from emp;
/*datadiff(str1,str2) str1-str2等于当前天数,日期天数计算函数

-- 38.显示姓名字段的任何位置包含"A"的所有员工的姓名. select * from emp where ename like '%A%';

-- 39.以年月日的方式显示所有员工的服务年限. -- 年

select *,datediff(now(),hiredate)/365 年 from emp;

-- 月

select *,datediff(now(),hiredate)/30 月 from emp;

-- 日

select *,datediff(now(),hiredate) 天数 from emp;

-- 40.显示员工的姓名和受雇日期,根据其服务年限,将最老的员工排在最前面.

select ename,hiredate,datediff(now(),hiredate)/365 年限
from emp
order by  年限 desc;

-- 43.对emp表中sal、comm进行加计算,并使用别名命令为员工的月总收入,同时展示出员工部门编号、员工姓名信息。

select deptno,ename,sal+ifnull(comm,0) as 月总收入
from emp;

-- 44.使用连接符查询emp表中员工的姓名和工资,并以如下格式列出且字段名展示为 TOTAL INCOME:

select concat(ename,sal) as "TOTAL INCOME" 
from emp;

-- 45.使用distinct排重查询emp中的job类型

select distinct job 
from emp;

-- 46.从emp表中找出奖金高于 薪水60%的员工

select ename
from emp
where ifnull(comm,0)>0.6*sal;

-- 47.找出部门10中所有经理(MANAGER)和部门20中所有办事员(CLERK)的详细资料。

select * from emp
where deptno=10 and job ='MANAGER' 
or deptno=20 and job='CLERK';

-- 48.从emp和dept中联合查询,并将员工编号、姓名、职位、地址信息列出。

select empno,ename,job,loc
from emp a,dept b
where a.deptno=b.deptno;

-- 49.统计各部门的薪水总和。

select deptno,sum(sal)
from emp
GROUP BY deptno;

-- 50.找出部门10中所有理(MANAGER),部门20中所有办事员(CLERK)以及既不是经理又不是办事员但其薪水大于或等2000的所有员工的详细资料。

select * from emp where job='MANAGER' and deptno=10 
or  job='CLERK' and deptno=20
or  job not in ('MANAGER','CLERK') and sal>2000 ;

-- 51.列出各种工作的最低工资。

select job,min(sal)
from emp 
group by job;

-- 52.列出各个部门的MANAGER(经理)的最低薪水。

select deptno,job,min(sal) 
from emp
where job='MANAGER'
group by deptno;

-- 53.列出有奖金的员工的不同工作。

select * 
from emp 
where comm is not null;

-- 54.找出无奖金或奖金低于300的员工。

select * from emp where comm is null or comm<300;

-- 55.显示所有员工的姓名,并使姓名首字母大写。

oracle有initcap函数
select  initcap(ename) from emp;

-- 56.显示正好为5个字符的员工的姓名。

select * 
from emp 
where length(ename)=5;

-- 57.显示不带有“R”的员工姓名。

select * 
from emp 
where ename not like '%R%';

-- 58.列出薪水高于在部门30工作的所有员工的薪水的员工姓名和薪水。

select * 
from emp 
where sal > all(select sal from emp where deptno=30);

-- 59.列出在每个部门工作的员工数量、平均工资和平均服务期限。

select deptno,count(ename) as 员工数量,avg(sal) as 平均薪资,avg(datediff(now(),hiredate)/365) as 平均年限
from emp  
group by deptno;

-- 60.列出从事同一种工作但属于不同部门的员工的一种组合。

select *
from emp a , emp b
where a.job = b. job and a.deptno <> b.deptno ;

-- 61.列出薪水比“SMITH”多的所有员工。

select * 
from emp 
where sal > (select sal from emp where ename='SMITH');

-- 62.列出至少有一个员工的所有部门。

select deptno,count(ename) as 员工
from emp
group by deptno
having 员工>1;

-- 63.对于每个员工,显示其加入公司的天数、月数、年数。

select ename,datediff(sysdate(),hiredate)/365 as 年, datediff(now(),hiredate)/30 as 月,datediff(now(),hiredate) as 天 、
from  emp;  
/*SYSDATE()与NOW(),显示当前系统时间

-- 64.对上题中的天数、月数、年数取整显示。

方法1:
select ename,round(datediff(sysdate(),hiredate)/365) as 年, round(datediff(now(),hiredate)/30) as 月,datediff(now(),hiredate) as 天 
from  emp;  /* round()  四舍五入法 */
方法2:
select ename,truncate(datediff(sysdate(),hiredate)/365,0) as 年, truncate(datediff(now(),hiredate)/30,0) as 月,datediff(now(),hiredate) as 天 
from  emp;   /* truncate() 阶段函数*/

-- 65.找出在每年5月受聘的所有员工。

select * 
from emp 
where date_format(hiredate,'%m')=5;

-- 66.显示在一个月为30天的情况下所有员工的日薪水,取整。

select ename,round(sal/30) as 日薪 
from emp;

-- 67.显示所有员工的姓名和加入公司的年份和月份,并将员工入职年月从低到高排序。

select ename,date_format(hiredate,'%Y-%m') as 入职年月
from emp
order by 入职年月;

-- 68.请查SMITH领导的薪水

方法1:
select boss.sal 
from emp boss,emp works
where boss.empno=works.mgr
and works.ename='SMITH';
方法2:
select sal 
from emp 
where empno = (select mgr from emp where ename='SMITH');

-- 69.请查SMITH领导的薪水和所在的部门地址

select a.sal,b.loc 
from emp a ,dept b
where a.deptno=b.deptno
and a.empno = (select mgr from emp where ename='SMITH');

-- 70.请查SMITH领导的薪水和所在的部门地址 以及领导的薪水等级

select a.sal,b.loc,c.grade
from emp a ,dept b, salgrade c
where a.deptno=b.deptno
and a.sal between losal and hisal
and a.empno = (select mgr from emp where ename='SMITH');

-- 71.查出SMITH的薪水等级

select sal,grade
from emp,salgrade
where sal between losal and hisal
and ename='SMITH';

-- 72.请查出SIMIH的薪水等级和他所在部门所在地

select sal,grade,loc
from emp a,dept b,salgrade 
where sal between losal and hisal
and a.deptno=b.deptno
and a.ename='SMITH';

-- 73.按照职位分组,求出每个职位的最大薪水

select job,max(sal)
from emp
group by job;

-- 74. -- I)求出每个部门中的每个职位的最大薪水

select deptno,job,max(sal)
from emp
group by deptno,job;

-- II)在薪水大于1000,并且职位不是MANAGER的员工中,求职哪个职位的平均薪水大于2000

select job,avg(sal)
from emp
where sal>1000
and job <> 'MANAGER'
group by job;

-- 75.列出SMITH的薪水和职位

select ename,sal,job from emp where ename='SMITH';

-- 76.列出SMITH的部门地址和补贴和薪水等级(等级表salgrade)

select a.ename,b.loc,ifnull(comm,0) as 补贴,grade
from emp a,dept b,salgrade
where a.deptno=b.deptno
and sal BETWEEN losal and hisal
and ename='SMITH';

-- 77.列出部门不是10,职位不是C开头的,薪资比公司平均薪资都高的员工名字

select *
from emp
where deptno <>10
and job not like 'C%'
and sal > (select avg(sal) from emp);

-- 78.哪个部门下面没有员工

select a.ename,b.deptno
from emp a right join dept b
on a.deptno=b.deptno;

-- 79.谁的薪水比SMITH多,同时部门又是和SCOTT的部门相同

select * 
from emp
where deptno = (select deptno from emp where ename='SCOTT')
and sal > (select sal from emp where ename='SMITH');

-- 80.列出薪资比每个部门每个职位的平均薪资还要高的员工

select *
from emp
where sal >all (select avg(sal) from emp group by deptno);

-- 81.SMITH的职位变更为SCOTT的职位

update  emp 
set job= (select b.job from (select job from emp where ename='SCOTT') b) 
where ename='SMITH';
/** You can't specify target table 'emp' for update in FROM clause 
mysql的子查询语句更新或删除不能在同一张表上,不然就会报这个错误。只要在套一层就解决啦。
参考: https://www.cnblogs.com/jeffen/p/7016547.html **/