只是小人物

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

 

序:为了方便举例,本文使用以下两张表的结构
有表emp_xxx和dept_xxx
dept_xxx结构如下
create table dept_xxx(
deptno number(2),
dname char(20),
location char(20));

插入数据
insert into dept_xxx values(10,'developer','beijing');
insert into dept_xxx values(20,'account','shanghai');
insert into dept_xxx values(30,'sales','guangzhou');
insert into dept_xxx values(40,'operations','tianjin');

emp_xxx结构如下
create table emp_xxx(
 empno number(4),
 ename varchar2(20),
 job varchar2(15),
 salary number(7,2),
 bonus number(7,2),
 hiredate date,
 manager number(4),
 deptno number(10)
);

insert into emp_xxx values(
  1001,' 牛宝宝','Manager',1000,2000,'12-MAR-10',1002,10);
insert into emp_xxx values(
  1002,' 黄容','Manager',1000,2000,'12-MAR=10',null,30);
insert into emp_xxx values(
  1003,' 李翔','Analyst',1000,2000,'12-4月-10',1001,20);
参照如上数据插入多条数据


注意:日期请根据当前参照如上数据插入多条数据
设置格式输入,(sqlplus中 默认DD-MON-RR)
若报错说MAR未找到,请用中文'五月'

1查询语句select

1.1列的别名

select 字段名 别名 from 表名


例子:计算员工的年薪
select ename ,salary , salary * 12 year_sar
from emp_xxx;
 -----year_sar 是salary*12的别名

1.2 复制表
create table 表名 as 查询语句;
例子:复制表emp_yyy为emp_xxx(xxx是原表,yyy是新表,下同 )
create table emp_yyy  as select * from emp_xxx;


例子:只复制结构,不复制数据
create table emp_yyy
as
select * from emp_xxx
where 1<>1;
注意:复制表的时候,不复制约束条件


注意:如果复制表时的查询语句中有表达式或者函数(包括单行函数和组函数),必须指定新表中的列名
指定方式:给列设置别名,或者在新表中设置列名


例子1:复制一部分数据(给列设置别名)
create table emp_yyy
as
select empno,ename,salary*12 year_sal      ------year_sal为新表的列名
from emp_xxx
where deptno = 10;
例子2:复制一部分数据(指定新表中的列名)
create table emp_yyy(name,year_sal)
as
select ename,salary*12
from emp_xxx;

1.3 distnct 关键字


distnct指所有列的唯一组合
作用:去除重复
select distnct 列名 from 表名


注意:distnct必须跟在select右边

例子:机构中有多少种职位?
select distinct job from emp_xxx;

1.4where条件查询


select * from 表名 where  条件

例子:薪水高于10000元的员工数据?
select * from emp_xxx where salary > 10000;

 

1.5大小写问题


select * from emp_xxx where job = 'Analys';
如果数据是analys,查不出结果
sql语句大小写不敏感,数据大小写敏感

 

1.6 betweend...and...关键字


1) 在区间中:bewteen低值 an  高值
2)闭区间:[低值,高值]

例子:薪水大于5000并且小于10000的员工数据?
select * from emp_xxx where salary between 5000 and 10000;
等同于
select * from emp_xxx where salary >= 5000 and salary <= 10000;

1.7 in (列表)


例子:列出职位是Manager或者Analyst的员工
select * from emp_xxx
where job in ('Manager','Analyst');
等同于
select * from emp_xxx where job = 'Manager' or job = 'Analyst';

1.8 模糊匹配 like%


1) '%' 表示()到多个字符,跟like配合使用
2) '_'下划线表示一个字符

例子:列出名字中包含有a字符的员工的数据?
selecr * from emp_xxx where ename like '%a%' ;


例子:列出名字中第二个字母是a的员工数据?
select * from emp_xxx where ename like '_a%';
注意:
如果要查询的数据中有特殊字符( 如_或%)
在做模糊查询时候,需要加上\符号表示转义,并且用escape短语指明转义字符\


例子:列出名字中以'S_"开头的名字?
select * from emp_xxx
where ename like 'S\_%'escape'\';

1.9 is null


数据库语言判断null值的方法.
例子:查询哪些员工没有奖金?
select * from emp_xxx where bonus is null;

1.10 not 关键字


可以用在not between
not in(list)
is not null


例子:查询哪些员工有奖金?
select * from emp_xxx where bonus is not null;

 

2 select查询语句中使用的函数

2.1 单行函数

2.1.1字符函数:

1) upper   转换为大写
2) lower   转换为小写
3) initcap   转换为首字母大写
4) length   取长度
5) lpad     左补丁
6) rpad     右补丁
7) replace   字符替换
8) trim    去除前后的空格


例子:将ename字段设置为10个长度,如果不够左边用"*"号补齐
select lpad(ename,10,"*") from emp_xxx;

例子:查找职位为"analyst"的员工  lower()
select * from emp_xxx where lower(job) = 'analyst';
例子:查找职位为''analyst"的员工 upper()
select * from emp_xxx where upper(job) = 'ANALYST';

2.1.2数字函数

trunc/round/mod
1)trunc
trunc(数字,小数点后的位数)用于截取
如果没有第二个参数,默认是0
例:
select ename, trunc(salary*0.1234567) s1
from emp_xxx;
2) round()
round(数字 , 小数点后的位数) 用于数字的四舍五入
计算金额的四舍五入
例: 
select ename,salary*0.1234567 s1, #保留原样
    round(salary*0.1234567) s2, #保留2位有效数字
    round(salary*0.1234567) s3 #默认0位有效数字
from emp_xxx;

3)mod() 

取模(取余数)
例子:求salary 对5000取模
select salary,mod(salary,5000) from emp_xxx;

1.2日期函数


1)months_between 两个日期之间的月分数
2)add_months 给定一个日期,为该日期增加指定月份
3)last_day 找出参数时间点所在的月份的最后一天

2.2.1 日期函数sysdate

例子:获取当前系统时间
select sysdate from dual;

 

2.2.2 虚表dual


 虚表dual是Oracle提供的用于操作函数的方式.用于SYS用户,共享给所有用户使用
 虚表dual是单行单列的表,表中存放一个常量数据X.
虚表的意义:更方便的操作函数或者查询常量

 

2.2.3日期数据相减
例子:计算员工入职多少天?
select ename,hiredate,(sysdate - hiredate) days
from emp_xxx;
 日期数据相减,得到两个日期之间的天数差,不足一天用小数表示.可以用round函数处理一下
select ename,hiredate,round(sysdate - hiredate) days
from emp_xxx;

 

2.2.4 日期函数months_between()
例:计算员工入职多少个月?保留小数.
select ename,hiredate,months_between(sysdate,hiredate) months
from emp_xxx;
例:计算员工入职多少个月?用整数表示
select ename,hiredate,
 round(months_between(sysdate,hiredate)) months
from emp_xxx;

 

2.2.5 日期函数add_months()
例子:计算12个月之前的时间点
select add_months(sysdate,-12) from dual;

 

2.2.6 日期函数last_day()
例子:计算本月的最后一天
select last_day(sysdate) from dual;

 

 

2.3转换函数
to_char/to_date/to_number

  to_char   to_number
日期  -------> 字符  ------------->  数字
  <------   <------------
  to_date   to_char

 

2.3.1 to_char()

to_char(日期数据,格式):把日期数据转换为字符数据


例子:把时间按指定格式输出
select to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss')
from dual;#2011-11-01 10:24:43

select to_char(sysdate, 'year month dd day dy')
from dual;#twenty twelve 5月  02 星期三 星期三

select to_char(sysdate,'yyyy/mm/dd')
from dual:#2012/05/02

例子:将7912345.67按指定格式$9,999,999.99输出
select to_char(791234567 , '$9,999,999.99')
from dual;

2.3.2日期格式

1) 常用日期格式
 yyyy  四位数字年:  如2011
 year  全拼的年:如 twenty eleven
 month 全拼的月 如:november或11月(中文)
 mm  两位数字月 如:11
 mon  简拼的月 如: nov(中文没有简拼)
 dd  两位数字日
 day  全拼的星期 如:tuesday或星期二
 dy  简拼的星期 如:tue
 am  上午/下午 如:am/pm


2)sqlplus中日期的默认格式为DD-MON-RR
alter session set nls_date_format = 'yyyy mm dd hh24:mi:ss';

 

2.3.3  to_date()

例子:插入一条数据,编号为1012,姓名为amy,入职时间为当前系统时间
insert into emp_xxx(empno, ename,hiredate)
values(1012, 'amy' , sysdate);
例子:插入一条数据,编号为1012,姓名为amy,入职时间为2011年10月10日
insert into emp_xxx(empno, ename,hiredate)
values(1012, 'amy' , to_date('2011-10-10','yyyy-mm-dd'));

 

2.3.4 to_number ()的用法
例子:将'$7,912,345.67'乘以10,输出结果
select to_number('$7,912,345.67','$9,999,999.99')*10
from dual;

 

2.3.5 小结: 转换函数to_date()和to_char()
to_date()和to_char()是时间处理的函数
 to_date()将字符串数据 按指定格式 转换为 日期数据
 to_char()将日期数据 按指定格式 转换为 字符串数据

 

2.4  其他函数nvl/coalesce/decode/case

 

2.4.1 coalesce(参数列表)函数的作用:


 返回参数列表中的第一个非空参数,参数列表中最后一个值通常为常量
例子:计算员工的年终奖金
要求:
1)如果bonus 不是null,发年终奖金金额为bonus
2)如果bonus 是null,发年终奖金金额为salary * 0.5
3)如果bonus 和 salary都是null,发100元安慰一下
select ename,bonus,salary,
 coalesce(bonus,salary*0.5,100) bonus
from emp_xxx;

2.4.2 nvl()函数(oracle中等价于coalesce),也是处理null值的
例子:计算平均奖金
1)如果bonus不为null,则用bonus计算
2)如果bonus为null,则以0计算
select avg(nvl(bonus,0)) from emp_xxx;

2.4.3 关于null值
1) 任何数据都可以取值null
2) 空值和字符串类作连接,结果就是字符串
3) 算术表达式中如果有null值,整个结果为null,处理null值用nvl函数
4) distinct 处理的数据有null,结果包含一个null值
5) 怎么判断一个字段的取值是否为null, is null不可以用=null,
      is not null 不可以用<>null
6) in后面的集合包含null值,结果集不受影响,not in后面的集合包含null值,结果集为null.

7)group by 分组时有null值,把所有的null值分在一组


2.4.4decode()函数
decode()函数是Oracle中等价于 case when语句的函数,作用同case语句相同

decode函数语法如下:
decode(判断条件,匹配1,值1,匹配2,值2,....,默认值)


表达的意思是:如果判断条件 = 匹配1, 则返回值 1
   判断条件 = 匹配2, 则返回值 2


例子:根据员工的职位,计算加薪后的薪水数据
要求:
1) 如果职位是Analyst:加薪10%
2) 如果职位Programmer:加薪5%
3) 如果职位是clerk:加薪2%
4) 其他职位:薪水不变
select ename,salary,job,
decode(job,'Analyst',salary*1.1,
  'Programmer',salary *1.05,
  'clerk', salary*1.02,
  salary) new_salary
from emp_xxx;

 

2.4.5 case语句
case语句是数据中的分支语句,相当于Java中的switch-case语句.
例子:根据员工的职位,计算加薪后的薪水数据
要求:
1) 如果职位是Analyst:加薪10%
2) 如果职位Programmer:加薪5%
3) 如果职位是clerk:加薪2%
4) 其他职位:薪水不变
select ename,salary,job,
case job when 'Analyst' then salary*1.1
      when 'Programmer' then salary*1.05
      when 'clerk' then salary * 1.02
else salary
end new_salary
from emp_xxx;


2.5函数的嵌套
函数的嵌套:f3(f2(f1(p1,p2),p3),p4)

2.6查询结果排序 order by
例子: 薪水由低到高排序(升序排序)
select ename,salary from emp_xxx
order by salary asc;   --正序排列,asc可以省略 desc降序(不可以省略)

例子:按入职时间排序,入职时间越早排在前面
select ename,hiredate
from emp_xxx
order by hiredate;

例子:按部门排序,同一部门按薪水由高到低排序
select ename,deptno,salary
from emp_xxx
order by deptno,salary desc;


2.7组函数
count()/avg()/min()/max()/sum()

例子员工表中有多少条记录
select count(*) from emp_xxx;


2.7.1数据字典user_tables
user_tables只读,不能改.
例子:当前帐户下有多少个表
select count(*) from user_tables;
例子:当前帐户喜爱有多少个名字中包含emp的表?
select count(*) from user_tables
where table_name like '%EMP%';
--like是模糊查询,%代边表0到多个字符,_代表一个字符
例子:入职时间不是null的数据总数
select count(hiredate) from emp_xxxl --注意: count函数忽略空值

2.8组函数 count()  avg()  sum()  max()  min()
 与单行函数如round(),to_date(),to_char(),coalesce()等不同,单行函数是每行数据返回一行结果,组函数是多行数据返回一行结果.


例子:计算员工的薪水总和是多少?
select sum(salary) from emp_xxx;


例子:计算员工的人数总和,薪水总和,平均薪水是多少?
错误写法:
select count(*) num,sum(salary) sum_sal, avg(salary) avg_sal
 from emp_xxx;
用avg(salary)只按有薪水的员工人数计算平均值,这样得到的数据不够准确, 也就是把薪水为null的过滤了

正确写法:
select count(*) num,sum(salary) sum_sal, avg(nvl(salary,0)) avg_sal
 from emp_xxx;


nvl(salary,0)就是当salary 为null时,以0来计算

 

例子:计算员工的最高薪水和最低薪水
select max(salary) max_sal, min(salary)  min_sal
from emp_xxx;

注意:
 组函数:count/avg/sum/max/min如果函数中写列名,默认忽略null值
 avg/sum针对数字的操作
 max/min对所有数据类型都可以操作

 

例子:计算最早和最晚的员工入职时间
select max(hiredate) max_hireddate, min(hiredate) min_hiredate
from emp_xxx;

 

2.9分组查询group by


group by 列名: 表示按指定列分组查询

例子:按部门计算每个部门的最高和最低薪水分别是多少?
select deprno,max(salary) max_s, min(salary) min_s
from emp_xxx
group by deptno;

例子:计算每个部门的薪水总和 和 平均薪水?
select deprno,sum(salary) sum_s, avg(nvl(salary,0)) avg_s
from emp_xxx
group by deptno;

例子:按职位分组,每个职位最高,最低薪水和人数?
select job,max(salary) max_s,
  min(salary) min_s,
  count(*) emp_num
from emp_xxx
group by job
order by emp_num;

注意:select后出现的列,凡是没有被组函数包围的列,必须出现在group by
否则会出错.
如果group by 短语中的列,没有出现select短语中,不会出错,信息不够全


2.10 having字句
having字句用于对分组后的数据进行过滤.


注意区别:
where是对表中数据的过滤,where后面是单行函数,不能跟组函数,可以跟表中的任意一列

having过滤的是组,having可以跟组函数,不能跟单行函数,可以跟组标识,不能跟任意列

执行过程是where在前,having在后

例子:平均薪水大于5000的部门数据,没有部门的不算在内
select deptno,round(avg(salary)) avgsal
from emp_xxx
where deptno is not null
group by deptno
having avg(nvl(salary,0)) >5000;

执行过程:from --->where--->group by --->having ---->select--->order by

例子:薪水总和大于20000元的部门数据?
select deptno,sum(salary) sum_s
from emp_xxx
where deptno is not null
group by deptno
having sum(salary) > 20000;

 

例子:列出20,30部门的平均工资,2种写法
写法1:
select deptno,round(avg(salary)) avg_s
from emp_xxx
where deptno in (20,30)
group by deptno;
执行过程:from -->where -->group by--->select
写法2:
select deptno,round(avg(salary)) avg_s
from emp_xxx
group by deptno
having deptno in(20,30);
执行过程:from --->  group by --->having --->select

例子:哪些部门人数超过2个人
select job,count(*) emp_num
from emp_xxx
where job is not null
group by job
having count(*) > 2;

3 非关联子查询

子查询 ----非关联子查询
子查询中的表和主查询的表之间没有建关联,即主查询的表中的字段和子查询的表中的字段没有写成条件表达式.
执行顺序:先执行子查询,当子查询的返回结果有多个时,把去重之后的结果传递给子查询

3.1单行比较运算符 > < >=  <=  =  <>


例子:薪资最高的人是谁?
select ename
from emp_xxx
where salary = (select max(salary) from emp_xxx);

例子:哪个部门的平均工资比20部门的平均工资高?
select deptno,round(avg(salary)) avg_s
from emp_xxx
group by deptno
having avg(salary) >
(select round(avg(salary)) from emp_xxx where deptno =20);

例子:谁的职位和'李翔'一样
select ename,job
from emp_xxx
where job = (select job from emp_xxx where ename = '李翔')
and ename <> '李翔';

3.2  All  Any  In


当子查询的返回结果是多个时,要用多值运算符.in  >any >all <ANY<ALL

例子:谁的薪水比'李翔'高? ---如果有多个叫'李翔'的人则会出错
select ename,salary
from emp_xxx
where salary > (select salary from emp_xxx where ename='李翔');

3.2.1 all


例子;当有多个'李翔时'查询谁的薪水比所有叫'李翔'的薪水都高?(大于最大值)
select ename,salary
from emp_xxx
where salary > ALL(select salary from emp_xxx where ename='李翔');

 

3.2.2 any
例子;当有多个'李翔时'查询谁的薪水比任意一个叫'李翔'的薪水都高?(大于最小值)
select ename,salary
from emp_xxx
where salary > ANY(select salary from emp_xxx where ename='李翔');

 

3.2.3 In


当只有一个'牛宝宝'的时候
例子:谁和'牛宝宝'同部门?列出除了'牛宝宝'以外的员工名字
select ename,salary job
from deptno = (select deptno from emp_xxx
   where ename = '牛宝宝')
and ename <> '牛宝宝';

当有多个'牛宝宝'
例子:例子:谁和'牛宝宝'同部门?列出除了'牛宝宝'以外的员工名字
select ename,salary job
from deptno in (select deptno from emp_xxx
   where ename = '牛宝宝')
and ename <> '牛宝宝';

例子:谁是'牛宝宝'的下属
select ename from emp_xxx
where manager in (select empno from emp_xxx
      where ename = '牛宝宝');

3.3总结:单行比较运算和All,Any,In
 根据子查询返回的行数选择使用:
 返回一行:>  <  >=  <=  <>
 返回多行:>ALL  > ANY  <ALL  <ANY  in

 

3.4子查询结果返回多列的情况


例子:每个部门拿最高薪水的是谁?
select ename
from emp_xxx
where (deptno,salary) in (select deptno,max(salary) from emp_xxx
   where deptno is not null
   group by deptno);


注意:子查询的条件是单列还是多列没关系,关键是要分清返回的是单行还是多行

 

3.5关联子查询


子查询中的表和主查询的表之间建关联,即主查询的表中的字段和子查询的表中的字段写成条件表达式

从主查询中的表中拿出第一条记录,把该记录相关字段的值带入到子查询中,执行子查询,再把该记录相关的字段的值与子查询的返回结果相比较,决定该记录是否放入结果集中,按上述方式依次执行主查询表中的没一条记录,关联子查询会执行多遍     


子查询中不再是独立的sql语句,需要依赖主查询传来的参数,这种方式叫关联子查询
例子:哪些员工的薪水比本部门的平均薪水低?
select ename,salary,deptno
from emp_xxx a
where salary < (select avg(nvl(salary,0))
   from emp_xxx b
   where b.deptno = a.deptno);

 

3.6 Exists 关键字


 exists关键字判断子查询有没有数据返回,有则为true,没有则为false
 exists不关心子查询的结果,所以子查询中select后面写什么都可以
exists的执行过程:
 从主查询的表中拿出第一条记录,进入子查询的表的第一条记录,查询这两条记录是否匹配关联表达式
 若匹配,余下的记录不再查询,exists成立,主表中的第一条记录放入结果集中
 若不匹配,接着检查,知道匹配返回,若子表中的所有记录都不匹配,第一条记录就被过滤掉.
 
例子:哪些人是其他人的经理?(查找有下属的员工)
方法一:使用关联子查询完成
select ename from emp_xxx a
where exists (select 1 from emp_xxx
   where manager = a.empno);


方法二:普通子查询
select ename from emp_xxx
where empno in (select distinct manager
   from emp_xxx);

例子:哪些部门没有员工?
select deptno,dname
from dept_xxx d
where not exists (select 'abc' from emp_xxx e
   where d.deptno = e.deptno)


注意:
exists保留
not exists过滤

例子:哪些人是员工?(哪些人不是别人的上属)
select ename
from emp_xxx o
where not exists
  (select 1 from emp_xxx i
  where o.empno = i.manager);


3.7 子查询总结
 非关联 in  / not in
 关联   exists/not exists
 in或exists用来解决匹配问题
 not in或not exists用来解决不匹配问题

 

4 集合操作

 

数据库中的查询语句的结果集(ResultSet) :集合A和集合B
集合A:{1,2,3,4,5}
集合B:{1,3,5,7,9}
A与B的合集:{1,2,3,4,5,7,9}
A与B交集:{1,3,5}
A与B的差集:A-B{2,4}


4.1结果集操作


1) 两个结果集必须结构相同(同构)
 当列的个数.列的顺序.列的数据类型一致,称这两个结果集结构相同
 只有结构相同的结果集才能做集合操作


2)合集  unionunion all
 union和union all的区别:
 union去掉重复记录,union all不去重
 union排序,union all不排序
 在满足功能的前提下,优选union all


例子:在10部门或者工资大于6000的人
select ename,salary
from emp_xxx
where deptno = 10
union
select ename,salary
from emp_xxx
where salary > 6000;

3)交集 intersect
例子:哪些人是领导?
select ename,empno from emp_xxx
intersect
select ename,manager from emp_xxx

4)差集 minus
例子:哪些人是员工?
select ename,empno from emp_xxx
minus
select ename,manager from emp_xxx

 

5.表间关联查询

 

5.1 表emp_xxx和表dept_xxx之间存在的参照关系
1) emp_xxx是所在部门(deptno)参照dept_xxx的部门编码(deptno)
2) dept_xxx是主表(父表),emp_xxx是从表(子表)

 

5.2 表emp_xxx自身存在一种参照关系
 员工的 经理(manager) 列参照 员工编码(empno) 列


5.3主键(PK)和外键(FK)(具体参看sql基础03--约束)


1) 主键(Primary key,简称 PK)   -----主键要求不重复,不能为null
 dept_xxx表的主键: 部门编码(deptno)
 emp_xxx的主键: 职员编码(empno)
2) 外键(Foreign key,简称FK)    ----- 外键参照主键的数据
 emp_xxx的所在部门(deptno)是外键,参照dept_xxx的主键
 emp_xxx的经理(mgr)列是外键,参照emp_xxx的主键

 

5.4内连接inner join (可以省略inner)


两张表做内连接,任意一张表的记录出现在结果集的前提条件是对另一表中能找到匹配的记录
join关键字用于连接两个表,语法如下:


表1 join 表2 on 条件


5.4.1等值连接(on 后面的条件是"=" 等于)


例子:列出员工的姓名和所在部门的名字和城市
select ename,dname,location
from emp_xxx e join dept_xxx d
on e.deptno = d.deptno;


注意:1)子表(emp_xxx)中的外键值(deptno)为null的数据不包含在结果集中
       2) 父表(dept_xxx)中主键值(deptno)没有被参照的数据不包含在结果集 中
       3)1对多关系,一个部门(deptno)对应多个员工(ename)

 

5.4.2自连接(等值连接的一种形式)


自然连接是等值连接的一种.表中的列外键关联自己表的主键列
自连接的数据来源只有一个表,通过使用表的别名虚拟成两个表的方式实现.

例子:列出工资大于4000的员工的姓名和他的上司的姓名
select t1.ename,t2.ename
from emp_xxx t1 join emp_xxx t2
on t1.manager = t2.empno
and t1.salary > 4000;

--t1表示从表,t2表示主表
--没有上司的员工不会列出

 

5.4.3非等值连接(on 后面的条件不是等值操作)

非等值连接指在多个表间使用非等号的连接,查询在多个表间有非等值关系的数据,非等值连接操作符包括:>,<,<>,>=,<=以及Between And,like in等
例子:列出工资级别是3级和5级的人数
select grade,count(*) from emp_xxx e inner join salgrade_xxx s
on e.salary between s.lowsal and s.hisal
and s.grade in (3,5)
group by s.grade;

5.4.4 驱动表和匹配表
表1 join 表2 on 条件
1) 表1叫做驱动表 , 表2叫做匹配表
2) 等值连接方式下,驱动表和起配表位置可以互换,不影响结果集
3)执行方式:不论谁作驱动表,都会遍历驱动表,在匹配表中查询匹配数据
4)谁作驱动表?优化器的模式是CBO,基于代价
哪张表作为驱动是系统根据当前表的数据统计信息,经过复杂计算得出,语法的顺序不影响执行计划


5.5 外连接outer join


1) 左外连接语法结构 : 表1 left outer join (left join) 表2 on 条件
2) 左外连接语法结构 : 表1 right outer join (righr join)表2 on 条件
3) 外连接的特征:
 如果驱动表在匹配表中找不到匹配记录,则匹配一行空行
 外连接的结果集 = 内连接的结果集 + 驱动表在匹配表中匹配不上的记录和空值
 外连接的本质是驱动表中的数据一个都不能少


 # left outer join以左边的表为驱动表
 # right outer join 以右边的表为驱动表

例子:
select ename,dname,location
from emp_xxx t1 join dept_xxx t2  ---t1 驱动表,t2匹配表
on t1. deptno = t2.deptno;
等价于
select ename,dname,location
from dept_xxx t1 join emp_xxx t2  ---t1 驱动表,t2匹配表
on t1.deptno = t2.deptno;

例子:列出每个员工和他的上级
select e1.ename,nvl(e2.ename,'no boss') 领导
from emp_xxx e1 left join emp_xxx e2
on e2.empno = e1.manager;

 

5.6full outer join 全外连接


1) 全外连接可以把两个表中的记录全部查出来
2) 全外连接的结果集 = 内连接的结果集  +  驱动表中在匹配表中找不到匹配记录的数据和null  +  匹配表在驱动表中找不到匹配记录的数据和null
例子
select e.empno,e.ename,d.deptno,d.dname
from emp_xxx e full outer join dept_xxx d
on e.deptno = d.deptno; 

 

5.7小结 外连接


1) 外连接的结果集 = 内连接的结果集 + 驱动表在匹配表中找不到匹配记录的数据和空值
2)驱动表和匹配表不能互换(全外连接除外)
3)写外连接的方式:
  a) 先写内连接
  b) 使用left 或 right 不重要,关键确定谁做驱动表
4)匹配表pk(主键) is null应用:解决否定问题,不是,不包含,匹配不上
 外连接 + where 匹配表.pk字段 is null


如:哪些部门没有员工
select d.deptno
from emp_xxx e right join dept_xxx d
on e.deptno = d.deptno
where e.empno is NULL ;

 

 

5.8 where 和inner join on的区别

 

sql1: select * from emp_xxx e,dept_xxx d
 where e.deptno = d.deptno;

sql2: select * from emp_xxx e inner join dept_xxx d;
 on e.deptno = d.deptno
执行结果完全相同, inner join 中 on后面的限制条件将全部起作用
,这与where的执行结果是完全一样的
即sql1和sql2的结果完全相同,具体区别如下
(1)where字句中使用的连接语句,在数据库语言中,被称为隐形连接.
inner join on字句产生的连接称为显性连接

二者产生的连接关系,没有本质区别,但隐形连接随着数据库语言的规范和发展,已经逐渐淘汰,比较新的数据库语言基本上已经抛弃了隐形连接,全部采用显性连接
(2)二者效率差不多

(3)关于select * from emp_xxx e inner join dept_xxx d;
 on e.deptno = d.deptno
 where e.salary>9000;
中where后的条件和on后的条件的区别
on后面的条件指的是内联的条件,where后面的条件指的是对内联后的结果集合进行筛选的条件.

5.9  oracle的中连接的语法

cross join
select
from t1,t2

inner join
select
from t1,t2
where t1.c1 =t2.c2
and t1.c2 = t2.c3

outer join
select
from t1,t2
where t1.c1 = t2.c2(+)
t1是驱动表,t2是匹配表


 

posted on 2012-05-16 01:00  只是小人物  阅读(1371)  评论(0编辑  收藏  举报