[Oracle数据库学习]四、多表查询
D2
多表查询
从多张表中获得数据。
笛卡尔集
产生笛卡尔集的条件:
1)省略连接条件;
2)连接条件无效;
3)所有表中的所有行相互连接。
SELECT * FROM employees;
| EMPLOYEE_ID | EMPLOYEE_NAME | DEPARTMENT_ID | JOB_ID | SALARY | COMMISSION_PCT | HIRE_DATE | DESCRIPTION |
|---|---|---|---|---|---|---|---|
| 1 | Alice | 1 | PM | 10000 | (null) | 2007-11-15T00:00:00Z | (null) |
| 2 | Bob | 1 | DEV | 5000 | 0.12 | 2017-03-10T00:00:00Z | abc%% |
| 3 | Cindy | 2 | QA | 6000 | 0.1 | 2010-04-15T00:00:00Z | abcd |
| 4 | Donald | 2 | AM | 4000 | 0.3 | 2019-01-05T00:00:00Z | ac%d |
| 5 | Elsa | 2 | DEV | 8000 | 0.12 | 2007-11-13T00:00:00Z | abc%% |
SELECT * FROM departments;
| DEPARTMENT_ID | DEPARTMENT_NAME | LOCATION_ID |
|---|---|---|
| 1 | Development | 1 |
| 2 | Trade | 2 |
SELECT employees.employee_name, departments.department_id FROM employees, departments;
| EMPLOYEE_NAME | DEPARTMENT_ID |
|---|---|
| Alice | 1 |
| Bob | 1 |
| Cindy | 1 |
| Donald | 1 |
| Elsa | 1 |
| Alice | 2 |
| Bob | 2 |
| Cindy | 2 |
| Donald | 2 |
| Elsa | 2 |
如何避免产生笛卡尔集:
在WHERE子句中加入有效的连接条件。
连接的类型
适用于SQL: 1999的连接:
交叉连接(Cross joins)
自然连接(Natural joins)
Using子句(Using clause)
完整或两个方向的外部连接(Full or two sided outer joins)
任意连接条件的外部连接(Arbitrary join conditions for outer joins)
适用于的连接Oracle 提供的连接(8i或更早):
等值连接(Equijoin)
不等值连接(Non-equijoin)
外连接(Outer join)
自连接(Self join)
--内连接是左边匹配右边表,有对应的则显示
--左连接是以左边表作为基准匹配右边表,如果右边表没有对应的则为null
--右连接是已右边表作为基准匹配左边表,如果左边表没有对应的则为null
--完全连接是左边表匹配右边表,如果有则显示没有则显示为null
--交叉连接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉连接也称作笛卡尔积。
D3
Oracle 连接
使用连接可以在多个表中查询数据:
1)在WHERE子句中写入连接条件;
2)如果多个表中有相同的列,在列名之前指定表名。
等值连接
SELECT table1.column, table2.column FROM table1, table2 WHERE table1.column1 = table2.column2;
SELECT employees.employee_name, employees.department_id, departments.department_id, departments.location_id FROM employees, departments WHERE employees.department_id = departments.department_id;
| EMPLOYEE_NAME | DEPARTMENT_ID | DEPARTMENT_ID | LOCATION_ID |
|---|---|---|---|
| Bob | 1 | 1 | 1 |
| Alice | 1 | 1 | 1 |
| Elsa | 2 | 2 | 2 |
| Donald | 2 | 2 | 2 |
| Cindy | 2 | 2 | 2 |
表的别名
使用表的别名简化查询。
SELECT e.employee_name, e.department_id, d.department_id, d.location_id FROM employees e, departments d WHERE e.department_id = d.department_id;
| EMPLOYEE_NAME | DEPARTMENT_ID | DEPARTMENT_ID | LOCATION_ID |
|---|---|---|---|
| Bob | 1 | 1 | 1 |
| Alice | 1 | 1 | 1 |
| Elsa | 2 | 2 | 2 |
| Donald | 2 | 2 | 2 |
| Cindy | 2 | 2 | 2 |
连接多个表
连接n个表,最少需要n-1个连接条件(避免出现笛卡尔集)。
SELECT e.employee_name, e.department_id, d.department_id, d.location_id, l.location_id, l.location_city FROM employees e, departments d, locations l WHERE e.department_id = d.department_id AND d.location_id = l.location_id;
| EMPLOYEE_NAME | DEPARTMENT_ID | DEPARTMENT_ID | LOCATION_ID | LOCATION_ID | LOCATION_CITY |
|---|---|---|---|---|---|
| Alice | 1 | 1 | 1 | 1 | Beijing |
| Bob | 1 | 1 | 1 | 1 | Beijing |
| Cindy | 2 | 2 | 2 | 2 | Shanghai |
| Donald | 2 | 2 | 2 | 2 | Shanghai |
| Elsa | 2 | 2 | 2 | 2 | Shanghai |
非等值连接
SELECT * FROM salary_grade;
| SALARY_GRADE | LOWEST_SALARY | HIGHEST_SALARY |
|---|---|---|
| A | 20000 | 30000 |
| B | 10000 | 19999 |
| C | 5000 | 9999 |
| D | 0 | 4999 |
可以查询表1的数据在表2数据范围内
EMPLOYEES表中的列工资应在JOB_GRADES表中的最高工资与最低工资之间
SELECT e.employee_name, e.salary, s.salary_grade FROM employees e, salary_grades s WHERE e.salary BETWEEN s.lowest_salary AND s.highest_salary
| EMPLOYEE_NAME | SALARY | SALARY_GRADE |
|---|---|---|
| Donald | 4000 | D |
| Bob | 5000 | C |
| Cindy | 6000 | C |
| Elsa | 8000 | C |
| Alice | 10000 | B |
外连接
使用外连接(符号是(+))可以查询不满足连接条件的数据。
SELECT * FROM departments;
| DEPARTMENT_ID | DEPARTMENT_NAME | LOCATION_ID |
|---|---|---|
| 1 | Development | 1 |
| 2 | Trade | 2 |
| 3 | Qulity | 4 |
SELECT * FROM locations;
| LOCATION_ID | LOCATION_CITY |
|---|---|
| 1 | Beijing |
| 2 | Shanghai |
| 3 | Chongqing |
可以看到DEPARTMENT_NAME是Qulity的LOCATION_ID=4没有出现在locations表中,
而LOCATION_CITY为Chongqing的LOCATION_ID=3没有出现在在departments中。
SELECT table1.column, table2.column FROM table1, table2 WHERE table1.column(+) = table2.column;
SELECT l.location_id, l.location_city, d.department_id FROM locations l, departments d WHERE l.location_id(+) = d.location_id;
| LOCATION_ID | LOCATION_CITY | DEPARTMENT_ID |
|---|---|---|
| 1 | Beijing | 1 |
| 2 | Shanghai | 2 |
| (null) | (null) | 3 |
左表无对应数据显示空。
SELECT table1.column, table2.column FROM table1, table2 WHERE table1.column = table2.column(+);
SELECT l.location_id, l.location_city, d.department_id FROM locations l, departments d WHERE l.location_id = d.location_id(+);
| LOCATION_ID | LOCATION_CITY | DEPARTMENT_ID |
|---|---|---|
| 1 | Beijing | 1 |
| 2 | Shanghai | 2 |
| 3 | Chongqing | (null) |
右表无对应数据显示空。
自连接
SELECT worker.employee_name, worker.manager_id, manager.employee_id, manager.employee_name FROM employees worker, employees manager WHERE worker.manager_id = manager.employee_id;
| EMPLOYEE_NAME | MANAGER_ID | EMPLOYEE_ID | EMPLOYEE_NAME |
|---|---|---|---|
| Elsa | 1 | 1 | Alice |
| Bob | 1 | 1 | Alice |
| Cindy | 2 | 2 | Bob |
worker和manager都保存在employees表中,用自连接得到对应关系数据。
使用SQL: 1999 语法连接
SELECT table1.column, table2.column FROM table1 [CROSS JOIN table2] | [NATURAL JOIN table2] | [JOIN table2USING (column_name)] | [JOIN table2ON(table1.column_name= table2.column_name)] | [LEFT|RIGHT|FULL OUTER JOIN table2 ON (table1.column_name= table2.column_name)];
叉集
等同于笛卡尔集;关键字为CROSS JOIN
SELECT departments.location_id, locations.location_id FROM departments CROSS JOIN locations;
| LOCATION_ID | LOCATION_ID |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 4 | 1 |
| 4 | 2 |
| 4 | 3 |
自然连接
自然连接使用NATURAL JOIN子句。
会以两个表中具有相同名字的列为条件创建等值连接,在表中查询满足等值条件的数据。
如果只是列名相同而数据类型不同,则会产生错误。
SELECT department_name, location_id, location_city FROM departments NATURAL JOIN locations;
| DEPARTMENT_NAME | LOCATION_ID | LOCATION_CITY |
|---|---|---|
| Development | 1 | Beijing |
| Trade | 2 | Shanghai |
采用相同的location_id列进行等值连接。
注意:不能使用表名或表的别名修饰相同的列。
SELECT department_name, locations.location_id, location_city FROM departments NATURAL JOIN locations;
ORA-25155: column used in NATURAL join cannot have qualifier
使用USING子句创建连接
NATURAL JOIN和USING子句经常同时使用。
在NATURAL JOIN子句创建等值连接时,可以使用USING子句,在有多个列满足条件时,指定等值连接中需要用到的列。
不要给选中的列中加上表名前缀或别名。
SELECT e.employee_name, d.location_id FROM employees e JOIN departments d USING (department_id);
| EMPLOYEE_NAME | LOCATION_ID |
|---|---|
| Alice | 1 |
| Bob | 1 |
| Cindy | 2 |
| Donald | 2 |
| Elsa | 2 |
使用ON子句创建连接
自然连接中是以具有相同名字的列为连接条件的。
可以使用ON子句指定额外的连接条件,这个连接条件是与其它条件分开的。
ON子句使语句具有更高的易读性。
SELECT e.employee_name, d.location_id FROM employees e JOIN departments d ON e.department_id = d.department_id;
| EMPLOYEE_NAME | LOCATION_ID |
|---|---|
| Alice | 1 |
| Bob | 1 |
| Cindy | 2 |
| Donald | 2 |
| Elsa | 2 |
使用ON子句创建多表连接
SELECT e.employee_name, d.department_name, l.location_city FROM employees e JOIN departments d ON e.department_id = d.department_id JOIN locations l ON d.location_id = l.location_id;
| EMPLOYEE_NAME | DEPARTMENT_NAME | LOCATION_CITY |
|---|---|---|
| Alice | Development | Beijing |
| Bob | Development | Beijing |
| Cindy | Trade | Shanghai |
| Donald | Trade | Shanghai |
| Elsa | Trade | Shanghai |
外连接
在SQL: 1999中,内连接只返回满足连接条件的数据。
两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行,这种连接称为左(或右)外联接。
两个表在连接过程中除了返回满足连接条件的行以外还返回两个表中不满足条件的行,这种连接称为满外联接。
左外连接
使用LEFT OUTER JOIN
SELECT l.location_id, l.location_city, d.department_id FROM locations l LEFT OUTER JOIN departments d ON l.location_id = d.location_id;
| LOCATION_ID | LOCATION_CITY | DEPARTMENT_ID |
|---|---|---|
| 1 | Beijing | 1 |
| 2 | Shanghai | 2 |
| 3 | Chongqing | (null) |
右外连接
使用RIGHT OUTER JOIN
SELECT l.location_id, l.location_city, d.department_id FROM locations l RIGHT OUTER JOIN departments d ON l.location_id = d.location_id;
| LOCATION_ID | LOCATION_CITY | DEPARTMENT_ID |
|---|---|---|
| 1 | Beijing | 1 |
| 2 | Shanghai | 2 |
| (null) | (null) | 3 |
满外连接
使用
FULL OUTER JOIN
SELECT l.location_id, l.location_city, d.department_id FROM locations l FULL OUTER JOIN departments d ON l.location_id = d.location_id;
| LOCATION_ID | LOCATION_CITY | DEPARTMENT_ID |
|---|---|---|
| 1 | Beijing | 1 |
| 2 | Shanghai | 2 |
| (null) | (null) | 3 |
| 3 | Chongqing | (null) |
增加连接条件
SELECT e.employee_name, d.location_id FROM employees e JOIN departments d ON e.department_id = d.department_id AND e.manager_id = 1;
| EMPLOYEE_NAME | LOCATION_ID |
|---|---|
| Bob | 1 |
| Elsa | 2 |
总结:
本节介绍多表连接查询。
1)Oracle连接:笛卡尔集、等值连接、非等值连接、外连接、自连接;
2)SQL连接:叉集(同笛卡尔集)、自然连接(USING子句)、ON子句、外连接(左外连接、右外连接、满外连接)。

浙公网安备 33010602011771号