-- 显示部门号为10的部门名字,员工名字和员工工资; MariaDB [scott]>select emp.ename,emp.sal,dept.dname from emp,dept where emp.deptno = dept.deptno and dept.deptno =10; +--------+---------+------------+ | ename | sal | dname | +--------+---------+------------+ | CLARK |2450.00| ACCOUNTING | | KING |5000.00| ACCOUNTING | | MILLER |1300.00| ACCOUNTING | +--------+---------+------------+ 3rowsinset (0.001 sec)
-- 显示各个部门员工的姓名,工资,工资级别 MariaDB [scott]>select emp.ename,emp.sal,salgrade.grade from emp,salgrade where emp.sal between losal and hisal; +--------+---------+-------+ | ename | sal | grade | +--------+---------+-------+ | SMITH |800.00|1| | ALLEN |1600.00|3| | WARD |1250.00|2| | JONES |2975.00|4| | MARTIN |1250.00|2| | BLAKE |2850.00|4| | CLARK |2450.00|4| | SCOTT |3000.00|4| | KING |5000.00|5| | TURNER |1500.00|3| | ADAMS |1100.00|1| | JAMES |950.00|1| | FORD |3000.00|4| | MILLER |1300.00|2| +--------+---------+-------+ 14rowsinset (0.001 sec)
3.自链接
所谓自连接,是在同一张表中进行链接和查询。
比如显示员工FORD上级领导的员工编号和姓名,我们可以用子查询,也可以用emp表的自链接来处理。
1 2 3 4 5 6 7 8 9 10
-- 使用子查询 select empno,ename from emp where emp.empno = (select mgr from emp where ename='FORD'); -- 使用多表查询(其实是给emp表起两个不同的别名) -- 如果不起别名,则无法自链接成功,因为没有办法区分两个emp表 -- 员工的领导编号和员工编号一致,即为领导用户的信息 select leader.empno,leader.ename from emp leader, emp worker where leader.empno = worker.mgr and worker.ename='FORD';
这种在一张表里面进行笛卡儿积的查询操作,就叫做自链接。最终都可以获取到正确结果
1 2 3 4 5 6
+--------+-------+ | empno | ename | +--------+-------+ | 007566 | JONES | +--------+-------+ 1 row in set (0.001 sec)
自链接本质上也是一个多表查询,只不过两个表都是emp表而已。
4.子查询
子查询指的是,将一个select查询语句作为子操作,嵌入到一个sql语句中;
我们可以把子查询的结果也当作是一张表来进行处理,这样一想就能理解子查询是怎么玩的了。
4.1 单行子查询
显示和SMITH同一个部门的员工
1 2
select*from emp where deptno = (select deptno from emp where ename='smith');
在这个查询中,子查询语句是select deptno from emp where ename='smith',这个语句返回的结果只有一行,所以被称为单行子查询。
select ename,job,sal,deptno from emp where job in (select job from emp where deptno=10) and deptno <>10; +-------+---------+---------+--------+ | ename | job | sal | deptno | +-------+---------+---------+--------+ | SMITH | CLERK |800.00|20| | JONES | MANAGER |2975.00|20| | BLAKE | MANAGER |2850.00|30| | ADAMS | CLERK |1100.00|20| | JAMES | CLERK |950.00|30| +-------+---------+---------+--------+ 5rowsinset (0.001 sec)
显示部门工资比30号部门所有员工工资都高的员工姓名、工资、部门号
1 2 3 4 5 6 7 8 9 10
select ename,sal,deptno from emp where sal >all(select sal from emp where deptno =30); +-------+---------+--------+ | ename | sal | deptno | +-------+---------+--------+ | JONES |2975.00|20| | SCOTT |3000.00|20| | KING |5000.00|10| | FORD |3000.00|20| +-------+---------+--------+ 4rowsinset (0.001 sec)
MariaDB [scott]> (select deptno,job from emp where ename like 'S%'); +--------+---------+ | deptno | job | +--------+---------+ | 20 | CLERK | | 20 | ANALYST | +--------+---------+ 2 rows in set (0.002 sec)
MariaDB [scott]> select ename from emp where (deptno,job) = any(select deptno,job from emp where ename like 'S%'); +-------+ | ename | +-------+ | SMITH | | SCOTT | | ADAMS | | FORD | +-------+ 4 rows in set (0.001 sec)
MariaDB [scott]> select ename from emp where (deptno,job) = all(select deptno,job from emp where ename like 'S%'); ERROR 1241 (21000): Operand should contain 1 column(s) MariaDB [scott]> select ename from emp where (deptno,job) in (select deptno,job from emp where ename like 'S%'); +-------+ | ename | +-------+ | SMITH | | SCOTT | | ADAMS | | FORD | +-------+ 4 rows in set (0.002 sec)
-- format函数用于限制小数点个数 select ename,deptno,sal,format(avgsal,2) from emp,(selectavg(sal) as avgsal,deptno as dt from emp groupby deptno) as temp where emp.sal > temp.avgsal and emp.deptno = temp.dt;
结果如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
MariaDB [scott]> select ename,deptno,sal,format(avgsal,2) -> from emp,(select avg(sal) as avgsal,deptno as dt from -> emp group by deptno) as temp -> where emp.sal > temp.avgsal and emp.deptno = temp.dt; +-------+--------+---------+------------------+ | ename | deptno | sal | format(avgsal,2) | +-------+--------+---------+------------------+ | ALLEN | 30 | 1600.00 | 1,566.67 | | JONES | 20 | 2975.00 | 2,175.00 | | BLAKE | 30 | 2850.00 | 1,566.67 | | SCOTT | 20 | 3000.00 | 2,175.00 | | KING | 10 | 5000.00 | 2,916.67 | | FORD | 20 | 3000.00 | 2,175.00 | +-------+--------+---------+------------------+ 6 rows in set (0.001 sec)
select ename,deptno,sal,format(avgsal,2) from emp,(selectavg(sal) as avgsal,deptno as dt from emp groupby deptno) as temp where emp.sal > temp.avgsal and emp.deptno = temp.dt;
首先将原有结果和薪资等级表进行笛卡尔积,然后再去掉无效的数据
1 2 3 4 5
-- 备注:这个SQL有错误! select*from salgrade,(select ename,deptno,sal,format(avgsal,2) from emp,(selectavg(sal) as avgsal,deptno as dt from emp groupby deptno) as temp where emp.sal > temp.avgsal and emp.deptno = temp.dt);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 4
正确的写法是给子查询加上一个表的别名,即可查询到笛卡尔积的结果
1 2 3 4 5
-- 更正:用于笛卡尔积的子查询需要有别名 select*from salgrade,(select ename,deptno,sal,format(avgsal,2) from emp,(selectavg(sal) as avgsal,deptno as dt from emp groupby deptno) as temp where emp.sal > temp.avgsal and emp.deptno = temp.dt) as subquery;
MariaDB [scott]> select * from salgrade,(select ename,deptno,sal,format(avgsal,2) -> from emp,(select avg(sal) as avgsal,deptno as dt from -> emp group by deptno) as temp -> where emp.sal > temp.avgsal and emp.deptno = temp.dt) as subquery limit 1; +-------+-------+-------+-------+--------+---------+------------------+ | grade | losal | hisal | ename | deptno | sal | format(avgsal,2) | +-------+-------+-------+-------+--------+---------+------------------+ | 1 | 700 | 1200 | ALLEN | 30 | 1600.00 | 1,566.67 | +-------+-------+-------+-------+--------+---------+------------------+ 1 row in set (0.001 sec)
select grade,ename,deptno,sal,asal from salgrade,(select ename,deptno,sal,format(avgsal,2) as asal from emp,(selectavg(sal) as avgsal,deptno as dt from emp groupby deptno) as temp where emp.sal > temp.avgsal and emp.deptno = temp.dt) as subquery where subquery.sal between losal and hisal;
这时候我们就成功得到了包含员工薪资等级的结果!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
MariaDB [scott]> select grade,ename,deptno,sal,asal from salgrade,(select ename,deptno,sal,format(avgsal,2) as asal -> from emp,(select avg(sal) as avgsal,deptno as dt from -> emp group by deptno) as temp -> where emp.sal > temp.avgsal and emp.deptno = temp.dt) as subquery -> where subquery.sal between losal and hisal; +-------+-------+--------+---------+----------+ | grade | ename | deptno | sal | asal | +-------+-------+--------+---------+----------+ | 3 | ALLEN | 30 | 1600.00 | 1,566.67 | | 4 | JONES | 20 | 2975.00 | 2,175.00 | | 4 | BLAKE | 30 | 2850.00 | 1,566.67 | | 4 | SCOTT | 20 | 3000.00 | 2,175.00 | | 5 | KING | 10 | 5000.00 | 2,916.67 | | 4 | FORD | 20 | 3000.00 | 2,175.00 | +-------+-------+--------+---------+----------+ 6 rows in set (0.001 sec)
小练习1
查询每个部门工资最高的人的姓名、工资、部门、最高工资。
1 2 3 4
select emp.ename, emp.sal, emp.deptno, ms from emp,(selectmax(sal) ms, deptno from emp groupby deptno) temp where emp.deptno=temp.deptno and emp.sal=temp.ms;
结果如下
1 2 3 4 5 6 7 8 9 10 11 12 13
MariaDB [scott]> select emp.ename, emp.sal, emp.deptno, ms -> from emp,(select max(sal) ms, deptno -> fr from emp group by deptno) temp -> where emp.deptno=temp.deptno and emp.sal=temp.ms; +-------+---------+--------+---------+ | ename | sal | deptno | ms | +-------+---------+--------+---------+ | BLAKE | 2850.00 | 30 | 2850.00 | | SCOTT | 3000.00 | 20 | 3000.00 | | KING | 5000.00 | 10 | 5000.00 | | FORD | 3000.00 | 20 | 3000.00 | +-------+---------+--------+---------+ 4 rows in set (0.001 sec)
小练习2
显示每个部门的信息(包括部门名字、编号、地址)和人员数量。
这个问题可以用多表查询或用子查询解决。
1 2 3 4 5
-- 使用多表 select dept.dname,dept.deptno,dept.loc,count(*) as mycnt from emp,dept where emp.deptno = dept.deptno groupby dept.deptno,dept.dname,dept.loc;
使用子查询的方式如下
1 2 3 4
select dept.deptno,dname,mycnt,loc from dept,(selectcount(*) as mycnt,deptno from emp groupby deptno) temp where dept.deptno=temp.deptno;
MariaDB [stu_test]>select*from stu,exam where stu.id = exam.id; +------+------+------+-------+ | id | name | id | grade | +------+------+------+-------+ |1| jack |1|56| |2| tom |2|76| +------+------+------+-------+ 2rowsinset (0.000 sec)
由此可知,直接使用笛卡尔积无法满足我们的要求。此时就可以用外连接了。
1 2 3
select*from stu leftjoin exam on stu.id = exam.id;