【Oracle学习10】SQL联接
关系理论的3个支柱是选择,投影和联接。
10.1 使用同等联接和非同等联接
10.1.1 联接的类型
1)内联接
关键词: natural join , using 和on.
#自然链接, 两表相同的列就会链接。
SQL> select region_name,country_name from regions natural join countries where country_name='Canada';
REGION_NAME COUNTRY_NAME
-------------------------------------------------- -----------------------------------------------------------
Americas Canada
SQL> select region_name,country_name from regions natural join countries where region_name='Americas';
#有多个相同列,都要相等并链接。
select employee_id,job_id,department_id,emp.first_name,emp.last_name from job_history jh natural join employees emp;
#指定链接的列名
SQL> select region_name,country_name from regions join countries using (region_id) where country_name='Canada';
REGION_NAME COUNTRY_NAME
-------------------------------------------------- ---------------------------------------------------------------------
Americas Canada
#显示join
SQL> select region_name,country_name from regions join countries on countries.region_id=regions.region_id where country_name='Canada';
#
SELECT employee_id, first_name, job_id, job_title
from employees NATURAL JOIN jobs;
说明:
自然链接,两表相同的列就会链接,如下有两个相同的列,department_id,manager_id.
#两表相同的列就会链接,如下有两个相同的列,department_id,manager_id
select count(*) from employees emp join departments using (department_id) where department_id>50; -- 51
select count(*) from employees natural join departments where department_id>50; --18
即相当于
select count(*) from employees ,departments where employees.department_id=departments.department_id and employees.manager_id=departments.manager_id and employees.department_id>50;
2)外联接
SQL1:未分配员工的部门有哪些?
SQL> select department_name , d.department_id ,e.last_name from departments d
left outer join employees e on e.department_id = d.department_id where e.department_id is null;
3)交叉联接
select count(*) from countries; #25
select count(*) from regions; #4
select count(*) from regions cross join countries; #100
#
select * from regions ;
select * from countries where country_id='CA';
select * from regions cross join countries where country_id='CA';
10.1.2 Oracle传统及ANSI SQL语法
1)Oracle 联接语法
- https://www.cnblogs.com/hehaiyang/p/4745897.html
#oracle传统语法,不使用ANSI连接,如inner join、left join、right join、full outer join,而使用(+)来表示外连接. 用(+)来实现, 这个+号可以这样来理解: + 表示补充,即哪个表有加号,这个表就是匹配表。如果加号写在右表,左表就是全部显示,所以是左连接。
#内链接
select region_name,country_name from regions , countries where regions.region_id = countries.region_id;
#左右链接
select * from t_A a left join t_B b on a.id = b.id; -- 左链接
select * from t_A a right join t_B b on a.id = b.id; -- 右链接
Select * from t_A a,t_B b where a.id=b.id(+); --左链接
Select * from t_A a,t_B b where a.id(+)=b.id; --右链接
#右外联接
select last_name,department_name from employees ,departments where employees.department_id (+) = departments.department_id;
#交叉链接或叫笛卡尔积
select region_name,country_name from regions , countries;
10.1.3 限定模糊的列名
select emp.employee_id,department_id,emp.manager_id,departments.manager_id from employees emp join departments using (department_id) where department_id>50;
#Do not qualify a column that is used in the NATURAL join or a join with a USING clause.
SQL> SELECT l.city, d.department_name
2 FROM locations l JOIN departments d
3 USING (location_id)
4 WHERE d.location_id = 1400;
WHERE d.location_id = 1400
*
ERROR at line 4:
ORA-25154: column part of USING clause cannot have qualifier
10.1.4 NATURAL JOIN 子句
NATURAL JOIN 若是没有相同的列名,则将成为笛卡尔积。若同列名类型不同且不兼容,都可能出错。
#
select * from locations natural join countries;
select * from locations , countries where locations.country_id= countries.country_id;
#若是没有列名相同,则将成为笛卡尔积
select count(*) from jobs natural join countries;
select count(*) from jobs , countries;
#
select employee_id,job_id,department_id,emp.first_name,emp.last_name from job_history jh natural join employees emp;
10.1.5 JOIN USING 子句
#USING 子句的列部分不能有限定词,会出错
select jh.employee_id,jh.job_id,jh.department_id,emp.first_name,emp.last_name from job_history jh join employees emp using (job_id,employee_id); #出错
select employee_id,job_id,jh.department_id,emp.first_name,emp.last_name from job_history jh join employees emp using (job_id,employee_id); -- rownum=2
select employee_id,job_id,department_id,emp.first_name,emp.last_name from job_history jh join employees emp using (job_id,employee_id,department_id);-- rownum=1
#自然链接
select employee_id,job_id,department_id,emp.first_name,emp.last_name from job_history jh natural join employees emp; ---rownum=1
#select jh.employee_id,jh.job_id,jh.department_id,emp.first_name,emp.last_name from job_history jh join employees emp on jh.job_id=emp.job_id;
1.10.6 JOIN ON
SQL1:
select * from departments d join employees e on (e.employee_id = d.department_id);
SQL2:
select * from departments d , employees e where e.employee_id = d.department_id;
10.1.7 N路联接和其它联接条件
多个表的联接。
#多表natural
select region_id,country_id,c.country_name,l.city,d.department_name
from departments d natural join locations l natural join countries c natural join regions r; --row=27
#error
#select count(*) from departments d natural join locations l , countries c , regions r; --rownum=2700
#JOIN ON
select r.region_id,c.country_id,c.country_name,l.city,d.department_name
from departments d join locations l on (l.location_id=d.location_id)
join countries c on ( c.country_id = l.country_id)
join regions r on (r.region_id = c.region_id); --rownum = 27
#JOIN USING
#using列中别加限定,如select r.region_id否则会错。ORA-25154: USING 子句的列不能有限定词
select region_id,country_id,c.country_name,l.city,d.department_name
from departments d join locations l using (location_id)
join countries c using (country_id )
join regions r using (region_id);
10.1.8 非同等联接
#非同等联接
select e.job_id ,last_name || 'can be double by changing jobs to: ' || j.job_id options , e.salary ,j.max_salary max_salary
from employees e join jobs j on (2*e.salary < j.max_salary) where e.salary > 11000 order by last_name;
10.2 自联接将表联接到自身
select f1.name Dad ,f2.name Child from family f1 join family f2 on (f1.id=f2.father_id);
#
select e.last_name employee , e.employee_id , e.manager_id , m.last_name, e.department_id from employees e join employees m
on (e.manager_id = m.employee_id) where e.department_id in (10,20,30) order by e.department_id;
10.3 使用外联接查看不满足联接条件的数据
10.3.1 内联接和外联接
外连接不仅可以返回符合连接和查询条件的数据行,而且还可以返回不符合条件的一些行。而内连接只能返回连接表中符合连接条件和查询条件的数据行,是不可以返回不符合条件的一些数据行。
示例:
10.3.2 左外联接
t1 left join t2 :t2数据以t1为准对齐,不足内容补为空值
t1 right join t2: t1数据以t2为准对齐,多于内容截掉不显示
SQL1:未分配员工的部门有哪些?
SQL> select department_name , d.department_id ,e.last_name from departments d
left outer join employees e on e.department_id = d.department_id where e.department_id is null;
DEPARTMENT_NAME DEPARTMENT_ID LAST_NAME
------------------------------------------------------------ ------------- --------------------------------------------------
Treasury 120
Corporate Tax 130
Control And Credit 140
Shareholder Services 150
SQL2:
SQL> select e.employee_id , e.department_id as e_depart, d.department_id as d_depart, d.department_name
from departments d left outer join employees e on ( d.department_id = e.department_id) where department_name like 'P%'; --rownum=8
EMPLOYEE_ID E_DEPART D_DEPART DEPARTMENT_NAME
----------- ---------- ---------- ------------------------------------------------------------
114 30 30 Purchasing
115 30 30 Purchasing
116 30 30 Purchasing
117 30 30 Purchasing
118 30 30 Purchasing
119 30 30 Purchasing
204 70 70 Public Relations
270 Payroll
SQL> select * from departments where department_name like 'P%';
DEPARTMENT_ID DEPARTMENT_NAME MANAGER_ID LOCATION_ID
------------- ------------------------------------------------------------ ---------- -----------
30 Purchasing 114 1700
70 Public Relations 204 2700
270 Payroll 1700
#内联接, 就会少department_id=270这条,即此department还没有分配一个员工。
SQL> select e.employee_id , e.department_id as e_depart, d.department_id as d_depart, d.department_name
from departments d join employees e on ( d.department_id = e.department_id) where department_name like 'P%';
EMPLOYEE_ID E_DEPART D_DEPART DEPARTMENT_NAME
----------- ---------- ---------- ------------------------------------------------------------
114 30 30 Purchasing
115 30 30 Purchasing
116 30 30 Purchasing
117 30 30 Purchasing
118 30 30 Purchasing
119 30 30 Purchasing
204 70 70 Public Relations
10.3.3 右外联接
t1 right join t2: t1数据以t2为准对齐,多于内容截掉不显示
#
SQL> select e.last_name,d.department_name,e.department_id
from departments d right outer join employees e on (e.department_id=d.department_id)
where e.last_name like 'G%';
LAST_NAME DEPARTMENT_NAME DEPARTMENT_ID
-------------------------------------------------- ------------------------------------------------------------ -------------
Gates Shipping 50
Gee Shipping 50
Geoni Shipping 50
Grant Shipping 50
Greene Sales 80
Greenberg Finance 100
Gietz Accounting 110
Grant
#有一个人没有Department
SQL> select e.first_name,e.last_name,e.department_id from employees e where last_name = 'Grant';
FIRST_NAME LAST_NAME DEPARTMENT_ID
---------------------------------------- -------------------------------------------------- -------------
Douglas Grant 50
Kimberely Grant
#
10.3.4 全外联接
全外联接返回左外联接和右外联接的组合结果。 传统的Oracle语法不支持全外联接,但可以通过UNION来结合左外联接,右外联接来实现。
#全外联接
select e.first_name,e.last_name , d.department_name from departments d full outer join employees e on (e.department_id = d.department_id) where e.department_id is null;
10.4 生成多个表的笛卡尔积
结果集是两个表的行数的乘积。无相同列名的自然联接会产生笛卡尔积。
select count(*) from jobs j cross join job_history; --rownum=190
select count(*) from jobs; -- 19
select count(*) from job_history; -- 10
select * from jobs j cross join job_history jh where j.job_id = 'AD_PRES';
10.5 总结
10.6 测试
#错误的SQL
#有natural 就不会有 using,on 等词
SQL> select * from employees natural join departments using (department_id);
ORA-00933: SQL command not properly ended
SQL> select * from employees join departments d using (d.department_id);
ORA-01748: only simple column names allowed here
SQL> select d.department_id,e.LAST_NAME from employees e join departments d using (department_id);
ORA-25154: USING 子句的列部分不能有限定词,即d.department等错了。
select department_id,e.LAST_NAME from employees e join departments d using (department_id); --ok
SQL> select job_id from job_history jh right outer join jobs j on (jh.job_id = j.job_id);
ORA-00918: column ambiguously defined