`

子查询转化为连接查询的例子

阅读更多
引用
   我们进行数据查询的时候极少有可能就在一张表里就能得到想要的数据,不可避免得会用到子查询或者连接查询,很多时候我们很轻松自然得会想到子查询的方法,但是子查询往往效率比较低,而转换成连接查询是一种很好的优化方式。

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

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

以下是一组测试数据:
Sql代码  
use mytest;   
drop table  if exists jobs;   
CREATE TABLE jobs(   
    employee varchar(30),   
    title varchar(30)   
);   
drop table if exists ranks;   
CREATE TABLE ranks(   
    title varchar(30),   
    rank varchar(30)   
);   
drop table if exists salary;   
CREATE TABLE salary(   
    rank varchar(30),   
    payment int(11)   
);   
  
insert into jobs values('张三','经理'),('李四','总经理'),('王五','总经理助理');   
insert into ranks values('经理','三'),('总经理','一'),('总经理助理','二');   
insert into salary values('一',20000),('二',8000),('三',7000),('四',7000);  

use mytest;
drop table  if exists jobs;
CREATE TABLE jobs(
	employee varchar(30),
	title varchar(30)
);
drop table if exists ranks;
CREATE TABLE ranks(
	title varchar(30),
	rank varchar(30)
);
drop table if exists salary;
CREATE TABLE salary(
	rank varchar(30),
	payment int(11)
);

insert into jobs values('张三','经理'),('李四','总经理'),('王五','总经理助理');
insert into ranks values('经理','三'),('总经理','一'),('总经理助理','二');
insert into salary values('一',20000),('二',8000),('三',7000),('四',7000);


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

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

Sql代码  
select payment from salary    
    where rank=(   
        SELECT rank from ranks    
            where title=(   
                SELECT title from jobs    
                    where employee='张三')   
);  

select payment from salary 
	where rank=(
		SELECT rank from ranks 
			where title=(
				SELECT title from jobs 
					where employee='张三')
);

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

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

select payment from salary s,ranks r,jobs j 
	where j.employee='张三' 
		and j.title = r.title 
		and s.rank = r.rank;

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

select salary.rank 
	from salary 
		where rank 
			not in(select rank from ranks);

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

select salary.rank 
	from salary left join ranks 
		on salary.rank=ranks.rank 
			where ranks.rank is null;

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

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


DROP TABLE if exists orders;
create table orders(
	customer varchar(30),
	whn date,
	totalitems int(11)
);
insert into orders values('jj','2010-10-10',5),
			('jj','2010-10-11',3),
			('jj','2010-10-12',1),
			('aa','2010-10-10',5),
			('bb','2010-10-10',8),
			('cc','2010-10-10',10);

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

select customer,whn,totalitems 
	from orders o1 where o1.totalitems=(
		SELECT max(totalitems) 
			from orders o2 
				where o1.customer = o2.customer
);

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

select o1.* from orders o1 join orders o2 
	on(o1.customer=o2.customer) 
		group by o1.customer 
			having o1.totalitems=max(o2.totalitems
);

相信这些我们大学的时候都已经学过,但是没有真正用起来的时候总是那么容易忘记,没有实际操作和体验是感觉不到它的需要,自然也不长记性了,而写下来又是另一种记住的方式。
分享到:
评论

相关推荐

    C#.net_经典编程例子400个

    165 实例113 波形图的绘制 166 4.2 图形转换 168 实例114 BMP转换成JPG格式 168 实例115 JPG转换成BMP格式 170 实例116 位图转化为WMF 171 实例117 Ico文件转化为位图 172 实例118...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part1

    实例054 包含数据库连接文件 85 实例055 包含网站头文件 86 实例056 包含网站尾文件 87 实例057 包含网站的主文件 88 2.4 条件语句 89 实例058 员工生日提醒 89 实例059 考试成绩评定标准 90 实例060 控制登录用户...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part2

    实例054 包含数据库连接文件 85 实例055 包含网站头文件 86 实例056 包含网站尾文件 87 实例057 包含网站的主文件 88 2.4 条件语句 89 实例058 员工生日提醒 89 实例059 考试成绩评定标准 90 实例060 控制登录用户...

    Toad 使用快速入门

     可以把查询结果以多种格式保存起来,可以保存为HTML,纯文本,XLS等多种格式 很容易的得到SQL函数的列表和用法描述(Show SQL help Window 按钮) 可以查看SQL语句的执行情况:通过下方的AutoTrace窗口 ,...

    花店管理系统-数据库设计.doc

    数据操作要求及实现 20 6.1数据插入、查询操作 20 6.2数据更新操作 20 6.3数据连接查询操作 21 7.总结 22 8.参考文献 24 花店管理系统 摘要: 我们已经学习了两个学期的数据库课程,所以对数据库的创建和SQL语言以及...

    华为编程开发规范与案例

    所以结构指针传入函数后,如要进行指针移动操作,最好先将其转化为_UC型再说。总之指针操作要小心为上。 3、避免指针的非法引用 【案例1.3.1】 【正 文】 在一次测试中,并没有记得做了什么操作,发现HONET系统的...

    freemarker总结

    2,使用+运算符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串再连接,如:${3 + "5"},结果是:35 使用内建的int函数可对数值取整,如: ${ (x/2)?int } ${ 1.1?int } ${ 1.999?int } ${ -1.1?int } ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    把模型数据转化为XML 14.5.1.4. 定义视图属性 14.5.1.5. 文档转换 14.5.2. 小结 14.6. 文档视图(PDF/Excel) 14.6.1. 简介 14.6.2. 配置和安装 14.6.2.1. 文档视图定义 14.6.2.2. Controller 代码 14.6.2.3. Excel...

    Spring 2.0 开发参考手册

    11.2.7. 执行查询 11.2.8. 更新数据库 11.3. 控制数据库连接 11.3.1. DataSourceUtils类 11.3.2. SmartDataSource接口 11.3.3. AbstractDataSource类 11.3.4. SingleConnectionDataSource类 11.3.5. ...

    COM技术内幕——微软组件对象模型--随书源代码

    6.4.3 将字符串转化成GUID 99 6.5 本章小结 101 第7章 类厂 102 7.1 CoCreateInstance 102 7.1.1 CoCreateInstance的声明 103 7.1.2 CoCreateInstance的使用 103 7.1.3 类上下文 104 7.1.4 客户程序清单 105 ...

    Java范例开发大全 (源程序)

     实例14 判断输入的年份是否为闰年 26  实例15 抽奖活动 27  3.2 for语句 28  实例16 小九九乘法表 28  实例17 如何列出素数 29  实例18 Java中的递归 31  实例19 男生女生各多少人 32  实例20 求...

    java范例开发大全(pdf&源码)

    实例226 携子之手 与子偕老(join) 415 实例227 线程让步(Yield) 417 实例228 会走动的钟(多线程) 419 实例229 变形金刚中的守护神(守护线程) 424 实例230 查看JVM中所有的线程的活动状况 426 实例231 模仿...

    java范例开发大全源代码

     实例14 判断输入的年份是否为闰年 26  实例15 抽奖活动 27  3.2 for语句 28  实例16 小九九乘法表 28  实例17 如何列出素数 29  实例18 Java中的递归 31  实例19 男生女生各多少人 32  实例...

    PHP基础教程 是一个比较有价值的PHP新手教程!

    字符被转化成数字,利用其最初位置。在PHP手册中有详细的例子。 数组与哈希表 数组与哈希表以同样的方法被支持。怎样运用取决于你怎样定义它们。你可以用list()或者array()来定义它们,也可以直接为数组赋值。数组...

    java范例开发大全

    实例226 携子之手 与子偕老(join) 415 实例227 线程让步(Yield) 417 实例228 会走动的钟(多线程) 419 实例229 变形金刚中的守护神(守护线程) 424 实例230 查看JVM中所有的线程的活动状况 426 实例231 模仿...

    Linux高级bash编程

    子shell(Subshells) 21. 受限shell(Restricted Shells) 22. 进程替换 23. 函数 23.1. 复杂函数和函数复杂性 23.2. 局部变量 23.3. 不使用局部变量的递归 24. 别名(Aliases) 25. 列表结构 26. 数组 27. ...

    Advanced Bash-Scripting Guide <>

    wh,whois 节点名字查询 4-7. 使用shift 5-1. echo 一些诡异的变量 5-2. 转义符 6-1. exit/exit 状态 6-2. 否定一个条件使用! 7-1. 什么情况下为真? 7-2. 几个等效命令test,/usr/bin/test,[],和/usr/bin/[ 7-3. 算数...

    spring chm文档

    11.2.7. 执行查询 11.2.8. 更新数据库 11.3. 控制数据库连接 11.3.1. DataSourceUtils类 11.3.2. SmartDataSource接口 11.3.3. AbstractDataSource类 11.3.4. SingleConnectionDataSource类 11.3.5. ...

Global site tag (gtag.js) - Google Analytics