`

子查询

 
阅读更多

   子查询转换成连接查询又可以分为两种情况,一种是不带聚合的子查询转换,另一种就是带有聚合函数的转换 

一、不带聚合函数的子查询转换: 

以下是一组测试数据: 

Sql代码  收藏代码
  1. use mytest;  
  2. drop table  if exists jobs;  
  3. CREATE TABLE jobs(  
  4.     employee varchar(30),  
  5.     title varchar(30)  
  6. );  
  7. drop table if exists ranks;  
  8. CREATE TABLE ranks(  
  9.     title varchar(30),  
  10.     rank varchar(30)  
  11. );  
  12. drop table if exists salary;  
  13. CREATE TABLE salary(  
  14.     rank varchar(30),  
  15.     payment int(11)  
  16. );  
  17.   
  18. insert into jobs values('张三','经理'),('李四','总经理'),('王五','总经理助理');  
  19. insert into ranks values('经理','三'),('总经理','一'),('总经理助理','二');  
  20. insert into salary values('一',20000),('二',8000),('三',7000),('四',7000);  


   建立了三个表,分别是jobs员工工作表,记录了员工的工作,第二表ranks是岗位等级表,记录每一个工作岗位的等级,第三个表slary自然就是HR为每一个等级的定的薪资标准了。 

    现在要知道张三的工资是多少,就需要使用三张表才能得到数据, 
使用子查询的方法如下: 

Sql代码  收藏代码
  1. select payment from salary   
  2.     where rank=(  
  3.         SELECT rank from ranks   
  4.             where title=(  
  5.                 SELECT title from jobs   
  6.                     where employee='张三')  
  7. );  


转换为连接查询的步骤大致有如下几点: 
1、使用表名或者表别名标记所有的列,如显jobs.employee 或者j.employee; 
2、将几个子查询的From子名中使用的相同的表用同一个名字或同一别名; 
3、将几个Form子句放在一起; 
4、将Select及查询的列删除; 
5、将第一个之后的Where替换成AND 

最后得到如下结果: 
Sql代码  收藏代码
  1. select payment from salary s,ranks r,jobs j   
  2.     where j.employee='张三'   
  3.         and j.title = r.title   
  4.         and s.rank = r.rank;  


对于需要排除某些条件的查询,如查询岗位等级表中在薪资表中没有工资级别的等级: 
Java代码  收藏代码
  1. select salary.rank   
  2.     from salary   
  3.         where rank   
  4.             not in(select rank from ranks);  

使用not in、exists、not exists不失为一种好方法,但同样可以转换成连接查询。如以上的查询可以转换为: 
Sql代码  收藏代码
  1. select salary.rank   
  2.     from salary left join ranks   
  3.         on salary.rank=ranks.rank   
  4.             where ranks.rank is null;  


二、带聚合函数的子查询向连接查询转换 

如下测试数据,有一个订单表,记录了销售人员每天的销售记录,测试数据如下: 
Sql代码  收藏代码
  1. DROP TABLE if exists orders;  
  2. create table orders(  
  3.     customer varchar(30),  
  4.     whn date,  
  5.     totalitems int(11)  
  6. );  
  7. insert into orders values('jj','2010-10-10',5),  
  8.             ('jj','2010-10-11',3),  
  9.             ('jj','2010-10-12',1),  
  10.             ('aa','2010-10-10',5),  
  11.             ('bb','2010-10-10',8),  
  12.             ('cc','2010-10-10',10);  



需要查询每一个销售员最高销售额的日期及销售额时,必然用的聚合函数MAX,以下是最容易想到的查询方式: 
Sql代码  收藏代码
  1. select customer,whn,totalitems   
  2.     from orders o1 where o1.totalitems=(  
  3.         SELECT max(totalitems)   
  4.             from orders o2   
  5.                 where o1.customer = o2.customer  
  6. );  

此时需要对每一行订单都要进行子查询,因此代码运行速度会很慢,并且老版本的MySQL还不支持子查询,只有一个表,要改成连接查询自然就是自连接了,这里我们需要使用Having子句, 
Sql代码  收藏代码
  1. select o1.* from orders o1 join orders o2   
  2.     on(o1.customer=o2.customer)   
  3.         group by o1.customer   
  4.             having o1.totalitems=max(o2.totalitems  
  5. );  

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics