3 3 3
例1:计量点电量信息表如下:Jlddl(jldbh,fjldbh,dl)
01 3000 02 01 300 03 01 400 04 5000
要求将父计量点电量改为(父计量点电量-子计量点电量之和) Update jdldl a
Set dl=dl-(select sum(dl) from jdldl b where a.jldbh=b.fjldbh //group by b.fjldbh(多余)) Where jldbh in (select fjldbh from jdldl);
//Where exists (select ‘’ from jlddl c where a.jldbh=c.fjldbh) 执行结果为:
Jlddl(jldbh,fjldbh,dl)
01 2300 02 01 300 03 01 400 04 5000
例2:两个表jdldl(jldbh,dl)以及jldgx(fjldbh,zjldbh,gx)
Jldbh dl 01 3000 02 300 03 400 04 5000 05 100 06 100
fjldbh zjldbh gx 01 02 套 01 03 套
01 06 执行主表力率 02 04 执行主表力率 03 05 套 update jdldl a
set dl=dl-(select sum(dl)
from jdldl b
where b.jldbh in (select zjldbh
from jldgx c
where a.jdlbh=c.fjldbh and c.gx=‘套’)
where jdlbh in (select fjldbh from jldgx where gx=‘套’);
//求所有有套表关系的父计量点的电量(减去子计量点后的电量)。 十五、 外连接(+):
例如: SELECT S1.SNO,NAME,CNO FROM STUDENT S1,SC S2 WHERE S1.SNO=S2.SNO(+);
11
按表S1中的学号选出:学号,姓名,课程号。如SC中没有的学号到S1中查找。 特别要求:外连接符号统一放在=右边
例如: SELECT S1.SNO,S1.NAME,S2.SNO,S2.NAME
FROM STUDENT S1,STUDENT S2 WHERE S1.SAGE=S2.SAGE(+)
AND S1.SSEX=’男’ AND S2.SSEX=’女’;
按男生的年龄(女生中没有但男生中有的年龄,按男生的年龄提取数据),选出相同年龄段的男生和女生的学号和姓名
A ( Aname , Abook)
张三 语文 李斯 数学 李斯 英语 王务 地理 赵六 历史 b (Aname, Bcredit) 张三 80 李斯 70 王务 55 李斯 90
语句1:select * from a ,b where a.Aname = b.Aname 返回6行数据
张三 语文 张三 80 李斯 数学 李斯 70 李斯 数学 李斯 90 李斯 英语 李斯 70 李斯 英语 李斯 90 王务 地理 王务 55
语句2:select * from a,b where a.Aname=b.Aname(+); 返回7行数据
张三 语文 张三 80 李斯 数学 李斯 70 李斯 数学 李斯 90 李斯 英语 李斯 70 李斯 英语 李斯 90 王务 地理 王务 55 赵六 历史 NULL NULL 十六、 子查询:
一个SELECT语句返回的结果就是一个集合,同时也可是看成是一个新的表,如果能够保证返回是一行一列,它本身又是一个数值。
例如1:SELECT * FROM SC WHERE SNO IN
(SELECT SNO FROM STUDENT WHERE SSEX=’女’); //返回所有女生的成绩
例如2: SELECT * FROM STUDENT
WHERE SAGE = (SELECT MAX(SAGE) FROM STUDENT);
等价与 SELECT * FROM STUDENT
WHERE SAGE in (SELECT MAX(SAGE) FROM STUDENT); //返回年龄最大的学生的基本信息
例如3:SELECT * FROM STUDENT WHERE
12
SAGE> (SELECT AVG(SAGE) FROM STUDENT); //返回年龄大于平均年龄的学生的基本信息。
特别说明:使用子查询能使所编写的sql语句在数据发生变化时语句不变化。例如:如上例3也可以用
语句select * from student Where sage>23;来表示,但是当平均年龄发生变化时,此语句就不能表示返回年龄大于平均年龄的学生的基本信息,所以还使用子查询来表示比较好。
十七、 存在测试EXISTS、NOT EXISTS
例如:SELECT * FROM SC WHERE SNO IN
(SELECT sno FROM STUDENT WHERE SSEX=’女’);
同:SELECT * FROM SC WHERE EXISTS
(SELECT * FROM STUDENT WHERE SSEX=’女’ AND SC.SNO=SNO);
返回所有女生的成绩
例如:SELECT * FROM SC
WHERE SNO
NOT IN (SELECT sno FROM STUDENT WHERE SSEX=’女’);
同:SELECT * FROM SC WHERE NOT EXISTS
(SELECT * FROM STUDENT WHERE SSEX=’女’ AND SC.SNO=SNO) 从表SC中选出性别不为女的记录
说明:使用EXISTS相比IN,当子查询检索到数据非常少时,使用in比exists快。反之,使用exists比in快。
如果exists后面的子句select * 改为select ‘’速度会更快。
子句中的使用的主句的列相对子句就是一个常量,系统首先找到主表符合条件的第一行,然后将主表那个列值取出来,作为常量替换到子句中,然后执行子句。理解真正理解这句话,也就知道了系统是如何处理一个语句的,能够理解什么时候能够使用索引,因此也就帮助你更加容易优化执行速度。 两个表table10(十万,bh主键)、table100(百万,bh主键)
Select * from table10 where 非索引条件 and exists (select ‘’ from table100 where table10.bh=table100 and 非索引条件);相对下面一句话要快
Select * from table10 where 非索引条件 and bh in (select bh from table100 where 非索引条件) 慢
十八、 子查询、连接查询的区别
例如:SELECT sc.* FROM SC WHERE SNO IN
(SELECT SNO FROM STUDENT WHERE SSEX=’女’);
等价:SELECT sc.* FROM SC ,student
WHERE sc.SNO =student.sno and SSEX=’女’; //返回所有女生的成绩
注意:如果其中一个表仅仅用来作为条件限制另外一个表,而不输出它的列,要求使用子查询,是使用子查询更加方便阅读。 极端的例子1:
例如:SELECT sc.* FROM SC where
sno in (select sno from student where sex=’女’ and 1………) And sno in (select sno from tab1 where t1=’1’ and 2………) And sno in (select sno from tab2 where s1=’2’ and 3………) And sno in (select sno from tab3 where t1=’3’ and 4………); 等价语句:
SELECT sc.* FROM SC ,student,tab1,tab2,tab3
WHERE sc.SNO =student.sno and SSEX=’女’and ……… and sc.sno=tab1.sno and tab1.t1=’1’ and ………
13
And sc.sno=tab2.sno and tab2.s2=’2’ and ……… And sc.sno=tab3.sno and tab3.t1=’3’ and ………;
关联方式可能速度快,那是因为系统能够优化考虑使用索引的结果,如果使用子句方式处理好in和exists速度同样。
后面这个语句经过多个人多次修改,书写格式不规范,更加难以阅读,超过7个以上就非常困难,同样的道理,编写程序同样强调的问题,程序不能够太大,否则就要分为几个子程序: SELECT sc.* FROM SC ,student,tab1,tab2,tab3
WHERE sc.SNO =student.sno and tab2.s1=’2’ and ……… and sc.sno=tab1.sno and tab3.t1=’3’ and ……… And sc.sno=tab2.sno and SSEX=’女’and ……… And sc.sno=tab3.sno and tab1.t1=’1’ and ………;
极端的例子2:如果是同一个表进行多次关联更复杂。
2、如果子查询中使用not in,采用连接的方式根本无法显示。选学过c语言的学生。 select * from student where sno in (select sno from sc where course=’c’)
等价:select student.* from student ,sc where student.sno=sc.sno and course=’c’ 没有选学过c语言的学生。
select * from student where sno not in (select sno from sc where course=’c’)
不等价:select student.* from student ,sc where student.sno=sc.sno and course<>’c’
3、另外一种子查询使用情况:其中一个表仅仅使用一个列,可以如下更加容易阅读理解: Select sno,c,…………
(select max(name) from student where sno=sc.sno) name from sc
where ………………;
4、严禁使用下面的格式:
Select (select v1 from t2 where t1.hh=hh and ……) from t1 where ……。 正确的格式:
Select v1 from t2 where ……
and hh in (select hh from t1 where ……) 十九、 联合语句 union
Select 语句的查询结果是元组的集合,所以多个select语句的结果可进行union操作。主要是应用在从两个以上表查询数据,将结果统一显示的情况。
1.下面语句将两个语句查询结果合并以后作为一个查询结果
Select * from软件学生档案where …… Union all
Select * from 应用学生档案 where ……;
2.下面语句将两个语句查询结果合并以后提出重复的值作为一个查询结果
Select * from 软件学生档案 where …… Union
Select * from 应用学生档案 where ……;
(例如:如果一个学生出现在union的前后两个select语句中,上面语句的查询结果中此学生会出现两次,而下面语句的查询结果中此学生只出现一次。) 二十、 程序易读要求
程序的质量重要指标:易读性 1、要求将下面语句修改为: Insert into t1
Select * from t2…… Union all
14
Select * from t3……;
拆分为两条语句:更加方便调试错误,特别是违反唯一性约束 Insert into t1
Select * from t2 ……; Insert into t1
Select * from t3……;
2、建议不使用或者少使用case函数进行数据修改或者插入。 Update t
Set v1=case when c1>c2 then c3 else c4 end; 建议采用几句话解决: Updae t Set v1=c3 Where c1>c2; Update t Set v1=c4
Where not c1>c2;
二十一、 关于索引使用方法
所谓使用索引,就是条件之中有一个列(所谓列不能是包含这个列的表达式)属于这个表的一个索引的第一个索引列,则查询时就能使用这个索引。
1.select * from student where sno='a'; 2.select * from student
where sno=’a’ and sname=’asdf’;
3.select * from student where sno=’a’ and sage=123; 4.select * from student
where sno=’a’ and sname =’asdf’ and sage=123; 5.select * from student where sname=’asdf’; 下面不能使用索引
6.Select * from student where substr(sname,1,2)=’SD’ 7.select * from student where trunc(birthday,’month’)=:ldt; 8.Select * from student where sname like ‘%SD%’ 下面能够使用索引,且等同上面
9.SELECT * FROM student where sname like ‘SD%’ 10.select * from student
where birthday>=trunc(:ldt,’day’)
and birthday
如果建立索引Create index on student(sno,sname,sage); 则语句1、2 、3、4可以使用这个索引,提高查询速度 如果再建立create index on student(sname,birthday) 则 语句5 、9、10能够使用这个新索引 语句6、7、8永远不能使用索引。
但是对于如下语句,在使用in比exists要快
d_dfjsd 数据非常多,索引使用dfjsdbh (khbh,ssny)
d_sj数据非常多,索引使用sjbh,但是每一个sjbh所查处的结果非常少 下面的语句前者慢,后者运行快. update d_dfjsd a set yjje=yjje -5
15