SQL(关联查询)

1.1. 关联基础

1.1.1. 关联的概念

实际应用中所需要的数据,经常会需要查询两个或两个以上的表。这种查询两个或两个以上数据表或视图的查询叫做连接查询,连接查询通常建立在存在相互关系的父子表之间。语法如下:

1. SELECT table1.column, table2.column

2. FROM table1, table2

3. WHERE table1.column1 = table2.column2;

或者:

1. SELECT table1.column, table2.column

2. FROM table1 JOIN table2

3. ON (table1.column1 = table2.column2);

(外键就是保存着另一张表的主键,作用就是产生关联关系,含有外键的表在关联关系中处于多的一方)

(多张表查询)当使用N张表查询,至少要有N-1个条件,否则可能产生笛卡尔积(笛卡尔积是数据库的第一杀手)

1.1.2. 笛卡尔积

笛卡尔积指做关联操作的每个表的每一行都和其它表的每一行做组合,假设两个表的记录条数分别是X和Y,笛卡尔积将返回X * Y条记录。当两个表关联查询时,不写连接条件,得到的结果即是笛卡尔积。例如:

1. SELECT COUNT(*) FROM emp; --14条记录

2. SELECT COUNT(*) FROM dept; --4条记录

3. SELECT emp.ename, dept.dname FROM emp, dept;--56条记录

1.1.3. 等值连接

等值连接是连接查询中最常见的一种,通常是在有主外键关联关系的表间建立,并将连接条件设定为有关系的列,使用等号”=”连接相关的表。例如查询职员的姓名、职位以及所在部门的名字和所在城市,使用两个相关的列做等值操作:

4.

4. SELECT *

5. FROM EMP,DEPT

6. WHERE EMP.DEPTNO = DEPT.DEPTNO;


关联关系通常使用等值连接。方法为(外键等于主键 

 

1.2. 关联查询

1.2.1. 内连接

内连接返回两个关联表中所有满足连接条件的记录。例如查询员工的名字和所在部门的名字:

1. SELECT e.ename, d.dname

2. FROM emp e, dept d

3. WHERE e.deptno = d.deptno


上面的语法也可以写为:

1. SELECT e.ename, d.dname

2. FROM emp e JOIN dept d

3. ON(e.deptno = d.deptno);

1.2.2. 外连接

内连接返回两个表中所有满足连接条件的数据记录,在有些情况下,需要返回那些不满足连接条件的记录,需要使用外连接,即不仅返回满足连接条件的记录,还将返回不满足连接条件的记录。比如把没有职员的部门和没有部门的职员查出来。外连接的语法如下:

1. SELECT table1.column, table2.column

2. FROM table1 [INNER | LEFT | RIGHT | FULL] JOIN table2

3. ON table1.column1 = table2.column2;

了解驱动表的概念。(左外连接,以左边的表为主,若不满足时补NULL)



外连接查询的例子,Emp表做驱动表:(左外链接,以EMP为主,)

1. SELECT e.ename, d.dname

2. FROM emp e LEFT OUTER JOIN dept d

3. ON e.deptno = d.deptno;


Dept表做驱动表:(右外连接,以Dept为主,EMP不全补NULL)

1. SELECT e.ename, d.dname

2. FROM emp e RIGHT OUTER JOIN dept d

3. ON e.deptno = d.deptno;

 

1.2.3. 全连接

全外连接是指除了返回两个表中满足连接条件的记录,还会返回布满足连接条件的所有其它行。即是左外连接和右外连接查询结果的总和。例如:

1. SELECT e.ename, d.dname

2. FROM emp e FULL OUTER JOIN dept d

3. ON e.deptno = d.deptno;

 


1.2.4. 自连接

自连接是一种特殊的连接查询,数据的来源是一个表,即关联关系来自于单表中的多个列。表中的列参照同一个表中的其它列的情况称作自参照表。

自连接是通过将表用别名虚拟成两个表的方式实现,可以是等值或不等值连接。例如查出每个职员的经理名字,以及他们的职员编码:


SELECT S.NAME AS 子类 ,F.NAME AS 父类 

 FROM ROOT S,ROOT F 

WHERE F.ID = S.FID;