认证目标:
- 使用同等连接和非同等连接编写select子句访问多个表的数据
- 使用自连接将表连接到自身
- 使用外连接查看不满足连接条件的数据
- 生成两个或多个表的笛卡尔乘积
关系理论的3个支柱:选择、投影和连接。
7.1 使用同等连接和非同等连接编写select语句访问多个表的数据
- 连接的类型
基本连接分为:同等连接和非同等连接
自然连接:当源表和目标表共享相同名称的列时,就可以执行自然连接,无需指定连接列。
select region_name
from regions natural join countries
where country_name='Canada'
select country_name
from countries natural join regions
where region_name='Americas';
当源表和目标表有多个相同列名时,您不需要它们作为连接列,可以使用join...using格式:
select region_name
from regions join countries using(region_id)
where country_name='Canada';
【注意】:如果Oracle没有强加任何规则表明两个离散表中具有相同名称的列必须彼此相关,如果regions表和countries表中有2列名称相同,那么等于这2列都作为连接条件。
join...on格式:不依赖于源表和目标表具有相同名称的列,允许显示表示连接列
select region_name
from regions a join countries b
on(a.region_id=b.region_id)
where country_name='Canada';
【注意】:除了join...on格式,一般不要使用其他格式的自然连接,因为数据库设计师在设计表结构的时候,并不一定保证都能做到不同表相关列的名称都相同。
2 外连接
假设employees和departments表由公共的department_id值连接,要想得到含空的department_id值以及departments表中没有department_id值的employess记录,就需要使用到外连接。
3 交叉连接
cross join 与笛卡尔积类似
select * from regions cross join
countries where country_id='CA';
4 Oracle连接语法:
传统的 Oracle连接语法支持:自然连接、外连接和笛卡尔积连接
--自然连接
select region_name
from regions,countries
where regions.region_id=countries.region_id;
--外连接
select department_name,last_name
from employees,departments
where employees.department_id(+)=departments.department_id;
--笛卡尔积
select * from regions,countries;
【注意】:外连接加号放置位置:如果出现在源表侧,那么目标表全匹配,源表中没有出现的,填空也要全匹配目标表,反之亦然。最简单的记法:加号在我这边,我要看(匹配)到你的全部。
- 使用SQL:1999语法连接表
Oracle9i之后,引入ANSI SQL:1999标准
语法:
select table1.column,table2.column
from table1
[natural join table2] |
[join table2 using (column_name)] |
[join table2 on (table1.column_name = table2.column_name)] |
[left |right|full outer join table2 on (table1.column_name=table2.column_name)] |
[cross join table2]
- 限定模糊列名
当2个关联的表中含有相同名称的列,而显示结果也包含此列时,那么会出现列名重复定义错误,为了解决此问题,必须制定列的来源:
select regions.region_id from regions,countries
- natural join语句
语法:
select table1.column,table2.column
from table1
natural join table2;
纯自然连接确定在table1和table2中具有公共名称的列,并使用所有这些列隐式连接这些表。
自然连接很简单,但基础薄弱,且存在风险,即使名称相同的2列没有任何关系,甚至没有兼容的数据类型,也会关联。
【注意】:natural join连接中的需要展示的列不能有限定词,例如:
select employees.employee_id from job_history natural join employees
--会报错:ORA-25155: NATURAL 联接中使用的列不能有限定词
- 自然join using语句
语法:
select table1.column,table2.column
from table1
join table2 using (join_column1,join_column2...);
纯自然连接有natural关键字,如果关键字natural和using出现在一个子句中,会报错。
using子句允许在using关键字中使用一个或者多个同等连接列。
using连接中展示列可以使用限定词,但是如果展示列包含using连接列时,不能出现限定词。
select e.last_name,e.first_name from job_history join employees e
using (job_id,employee_id)
- 自然join on 语句
语法:
select table1.column,table2.column
from table1
join table2 on(table1.column_name = table2.column_name)
natural join和join using子句依赖具有相同列名的连接列。
join...on子句允许显式指定连接列,而不必担心它们的列名是否相同,但是连接列的数据类型必须相同或可以隐式转换。
join...on是最灵活、最常用的形式。
select e.last_name,j.job_id
from employees e
join job_history j
on(e.employee_id=j.department_id)
问:要求从多个表中检索信息,分组结果,并运用聚集函数。可以依据来自多个表源的数据使用分组函数吗?
答:可以,连接多个表最终生成一组数据集,再使用聚集函数,就像这些数据来自于一个表源一样。
问:当连接2个表时,它们之间存在一种风险,即包含公共列名,如果这些列出现在select子句中,Oracle知道从哪个表中获得数据吗?
答:不知道,会报错,要使用限定词来避免模糊引用。
问:natural join子句依据共享相同值的公共名称的列连接2个表的行,可以依据某些而不是全部的共享列来连接2个表吗?
答:可以,使用join...using语句。
- N路连接和其他连接条件
select e.last_name,e.salary,l.city from employees e
join departments d on (d.department_id=e.department_id and salary > 12000)
join locations l on (l.location_id=d.location_id)
- 非同等连接
非同等连接根据不相等表达式匹配不同表中的列值。将源表中各行连接列的值与目标表中相应值进行比较,如果连接中使用的表达式计算为true,就会找到匹配。
使用join...in语句指定非同等连接,但连接条件包含<>,>,<,>=,<=等
语法:
select table1.column,table2.column
from table1
[join table2 on (table1.column_name < table2.column_name)]
7.2 使用自连接将表连接到自身
使用join...on将表连接到自身
select a1.catalog_name catalog_name,a2.catalog_name parent_catalog_name
from catalog a1
join catalog a2 on(a1.parent_catalog_id=a2.catalog_id)
--catalog表结构:catalog_id,catalog_name,parent_catalog_id
--其中parent_catalog_id为每一个catalog_id的父记录ID
7.3 使用外连接查看不满足连接条件的数据
- 内连接
内连接也叫连接,是最早的一种连接,最早被称为普通连接或自然连接。内连接是从结果中删除其他被连接表中没有匹配行的所有行,所以内连接可能会丢失信息。
- 外连接
外连接则扩充了内连接的功能,会把内连接中删除表源中的一些保留下来,由于保留下来的行不同,把外连接分为左外连接、右外连接和全外连接这3种连接。
- 左外连接
select table1.column,table2.column
from table1
left outer join table2
on (table1.column=table2.column)
左外连接返回join关键字左边表因为不满足连接条件而被排除的行。
select e.last_name,d.department_name,d.department_id
from employees e
left outer join departments d
on (e.department_id=d.department_id)
最后返回的结果:LAST_NAME为Grant的department_id为空,亦然有结果返回,如果使用自然连接(内连接),是不会有这一行的返回的。
select e.last_name,d.department_name,d.department_id
from departments d
left outer join employees e
on (e.department_id=d.department_id)
这一个查询返回的结果包含了departments表中所出现的所有部门的记录,即使employees表中没有出现这个department_id。
- 右外连接
和左外连接相反。
语法:
select table1.column,table2.column
from table1
right outer join table2
on (table1.column=table2.column)
select e.last_name,d.department_name,d.department_id
from departments d
right outer join employees e
on (e.department_id=d.department_id)
select e.last_name,d.department_name,d.department_id
from employees e
left outer join departments d
on (e.department_id=d.department_id)
上面2个查询的功能相同。
- 全外连接
语法:
select e.last_name,d.department_name,d.department_id
from departments d
full outer join employees e
on (e.department_id=d.department_id)
左右外连接只能返回join一边不满足条件的结果,而full join则返回所有结果。
select e.last_name,d.department_name,d.department_id
from departments d
full outer join employees e
on (e.department_id=d.department_id)
上面的查询,只要包含department_id,无论是空值还是不能匹配的,都能找出来。