从多个表中获取数据 


从多个表中获取数据


显示来自多个表的数据

大型数据库的相关表通过使用外键和主键或通常称为公用列的方式链接在一起。联接表的能力将使您能够为生成的结果表添加更多含义。对于要在查询中联接的’n’个数字表,最小(n-1)个联接条件是必需的。根据联接条件,Oracle组合匹配的一对行并显示满足联接条件的行。

联接分类如下

  • 自然连接(也称为等值连接或简单连接)-使用通常命名和定义的列创建连接。

  • 非等分联接-当表中没有等效行要联接时联接表,例如,使表的一列中的值与另一表中的值范围匹配。

  • 自联接-将表联接到自身。

  • 外部联接-当另一个表中没有匹配的记录时,在输出中包括一个表的记录。

  • 笛卡尔联接(也称为笛卡尔乘积或交叉联接)-将第一个表的每一行与第二个表的每一行进行复制。通过显示所有可能的记录组合在表之间创建联接。

自然加入

NATURAL关键字可以简化等值联接的语法。只要两个(或多个)表的列名称相同且这些列是联接兼容的,即列具有值的共享域,就可以使用NATURAL JOIN。操作将表中具有相同命名列的列值相等的行连接起来。

考虑一下DEPARTMENTS和EMPLOYEES表之间的一对多关系,每个表都有一个名为DEPARTMENT_ID的列,该列是DEPARTMENTS表的主键和EMPLOYEES表的外键。

SELECT E.first_name NAME,D.department_name DNAME
FROM employees E NATURAL JOIN departments D;

FIRST_NAME DNAME
---------- ------
MILLER     DEPT 1
JOHN       DEPT 1
MARTIN     DEPT 2
EDWIN      DEPT 2

下面的SELECT查询通过使用ON关键字显式指定连接条件来连接两个表。

SELECT E.first_name NAME,D.department_name DNAME
FROM employees E JOIN departments D
ON (E.department_id = D.department_id);

关于NATURAL JOIN有一些限制。您不能使用NATURAL JOIN指定LOB列。此外,联接中涉及的列也不能通过表名或别名来限定。

使用条款

使用自然连接,Oracle隐式标识列以形成连接的基础。许多情况下需要明确声明连接条件。在这种情况下,我们使用USING子句指定连接条件。由于USING子句基于列的相等性连接表,因此也称为Equijoin。它们也称为内部联接或简单联接。

句法:

SELECT <column list="">
FROM   TABLE1   JOIN   TABLE2    
USING (column name)</column>

考虑下面的SELECT查询,使用公用列DEPARTMENT_ID将EMPLOYEES表和DEPARTMENTS表联接。

SELECT E.first_name NAME,D.department_name DNAME
FROM employees E JOIN departments D
USING (department_id);

自我加入

当单个表中存储的行之间存在相关关系时,SELF-JOIN操作将生成结果表。换句话说,将表联接到自身时,该联接称为“自联接”。

考虑包含雇员及其报告管理者的EMPLOYEES表。要查找雇员的管理者姓名,需要在EMP表本身上进行联接。这是“自我加入”的典型候选人。

SELECT e1.FirstName Manager,e2.FirstName Employee
FROM employees e1 JOIN employees e2
ON (e1.employee_id = e2.manager_id)
ORDER BY e2.manager_id DESC;

非等值

当相关列不能用等号连接时,将使用非等距联接,这意味着表中没有等效的行要联接。非等距联接使您可以将范围的最小值存储在一个列中记录的值和另一列中的最大值。因此,您可以使用非等距联接来确定要运输的物品是否在列的最小和最大范围之间,而不是查找列与列的匹配。如果联接确实找到了该物品的匹配范围,则对应的运输费用可以在结果中返回。与传统的相等联接方法一样,可以在WHERE子句中执行非相等联接。另外,可以将JOIN关键字与ON子句一起使用,以指定用于连接的相关列。

SELECT E.first_name,
            J.job_hisal,
            J.job_losal,
            E.salary
     FROM employees E JOIN job_sal J
     ON (E.salary BETWEEN J.job_losal AND J.job_losal);

我们可以使用前面讨论的所有比较参数,例如相等和不相等运算符,BETWEEN,IS NULL,IS NOT NULL和RELATIONAL。

外连接

外部联接用于标识一个表中的行与第二个表中的行不匹配的情况,即使两个表是相关的。

外部联接共有三种类型:左,右和全外联接。它们都以INNER JOIN开头,然后添加回一些已删除的行。 LEFT OUTER JOIN将加入条件中从第一个(左)表删除的所有行加回去,并将第二个(右)表的输出列设置为NULL。 RIGHT OUTER JOIN加回在连接条件下从第二个(右)表删除的所有行,并且第一个(左)表的输出列设置为NULL。 FULL OUTER JOIN重新添加从两个表中删除的所有行。

右外连接

RIGHT OUTER JOIN加回在连接条件下从第二个(右)表删除的所有行,并且第一个(左)表的输出列设置为NULL。请注意,以下查询列出了员工及其相应部门。同样,没有员工被分配到部门30。

SELECT E.first_name, E.salary, D.department_id          
FROM employees E, departments D
WHERE E.DEPARTMENT_ID (+) = D.DEPARTMENT_ID;

FIRST_NAME SALARY     DEPARTMENT_ID
---------- ---------- ----------
JOHN       6000       10
EDWIN      2000       20
MILLER     2500       10
MARTIN     4000       20
                      30

左外连接

LEFT OUTER JOIN将加入条件中从第一个(左)表删除的所有行加回去,并将第二个(右)表的输出列设置为NULL。通过交换(+)符号的位置,上面演示的查询可用于演示左外部联接。

SELECT E.first_name, E.salary, D.department_id
FROM employees E, departments D
WHERE   D.DEPARTMENT_ID = E.DEPARTMENT_ID (+);

FIRST_NAME SALARY     DEPARTMENT_ID
---------- ---------- ----------
JOHN       6000       10
EDWIN      2000       20
MILLER     2500       10
MARTIN     4000       20
                      30

完全外部加入

FULL OUTER JOIN重新添加从两个表中删除的所有行。以下查询显示了员工及其所在部门。请注意,到目前为止,尚未为员工“ MAN”分配任何部门(它为NULL),并且未将部门30分配给任何员工。

SELECT  nvl (e.first_name,'-') first_name, nvl (to_char (d.department_id),'-') department_id
FROM employee e FULL OUTER JOIN department d
ON e. depARTMENT_ID = d. depARTMENT_ID;

FIRST_NAME DEPARTMENT_ID
---------- --------------------
MAN        -
JOHN       10
EDWIN      20
MILLER     10
MARTIN     20
-          30

6 rows selected.

笛卡尔积或交叉联接

对于两个实体A和B,A * B被称为笛卡尔积。笛卡尔乘积由每个表中的行的所有可能组合组成。因此,将10行的表与20行的表联接在一起时,笛卡尔乘积为200行(10 * 20 = 200),例如,将雇员表与8行联接,将部门表与3行联接将产生24行的笛卡尔乘积表(8 * 3 = 24)。

交叉联接是指两个表的笛卡尔积。它产生两个表的叉积。可以使用CROSS JOIN子句编写以上查询。

笛卡尔积结果表通常不是很有用。实际上,这样的结果表可能会造成极大的误导。如果对EMPLOYEES和DEPARTMENTS表执行以下查询,则结果表表明每个员工与每个部门都有关系,我们知道事实并非如此!

SELECT E.first_name, D.DNAME
FROM employees E,departments D;
SELECT E.first_name, D.DNAME
FROM employees E CROSS JOIN departments D;
0



error: 内容受到保护 !!