我正在玩连接并发现这个奇怪的问题:
我试过这样的事情:
SELECT *
FROM ((EMPLOYEES INNER JOIN DEPARTMENTS USING(DEPARTMENT_ID))
NATURAL JOIN LOCATIONS);
结果是106行。然后,我只想选择那些CITY属性等于多伦多'的行,所以我这样做了:
SELECT *
FROM ((EMPLOYEES INNER JOIN DEPARTMENTS USING(DEPARTMENT_ID))
NATURAL JOIN LOCATIONS)
WHERE CITY = 'Toronto';
结果恰好包含两行,其中CITY等于'多伦多'我需要的。但是,我不需要所有列,因此我将查询更改为
SELECT LAST_NAME, JOB_ID, DEPARTMENT_ID, DEPARTMENT_NAME, CITY
FROM ((EMPLOYEES INNER JOIN DEPARTMENTS USING(DEPARTMENT_ID))
NATURAL JOIN LOCATIONS)
WHERE CITY = 'Toronto';
这给了我106行,CITY总是设置为'多伦多',这对我没有任何意义。另一个奇怪的事情是,当我选择属性LOCATION_ID时,结果是正确的(我想要的2行)。
以下是相关关系架构:
describe EMPLOYEES
Name Null Type
-------------- -------- ------------
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
JOB_ID NOT NULL VARCHAR2(10)
DEPARTMENT_ID NUMBER(4)
describe DEPARTMENTS
Name Null Type
--------------- -------- ------------
DEPARTMENT_ID NOT NULL NUMBER(4)
DEPARTMENT_NAME NOT NULL VARCHAR2(30)
MANAGER_ID NUMBER(6)
LOCATION_ID NUMBER(4)
describe locations
Name Null Type
-------------- -------- ------------
LOCATION_ID NOT NULL NUMBER(4)
CITY NOT NULL VARCHAR2(30)
我知道我可以用50种不同且更简单的方式编写此查询,但我想知道这有什么问题。我使用Oracle SQL Developer。
谢谢
答案 0 :(得分:3)
不知道出了什么问题但不使用天然连接。而是明确定义连接。自然连接为您自动执行操作。编程时不是一件好事。
SELECT LAST_NAME, JOB_ID, DEPARTMENT_ID, DEPARTMENT_NAME, CITY
FROM EMPLOYEES INNER JOIN DEPARTMENTS USING(DEPARTMENT_ID)
JOIN LOCATIONS ON (locations.location_id = departments.location_id)
WHERE CITY = 'Toronto';
Hartstein MK_MAN 20 Marketing Toronto
Fay MK_REP 20 Marketing Toronto
并且丢失括号,它们令人困惑,在这里毫无用处。
编辑: 解释计划显示位置上有笛卡尔积。因此,自然联接无法找到连接条件并且可以使用cartasian产品。 再一次:天然联合是邪恶的;-) 请参阅:http://en.wikipedia.org/wiki/Join_(SQL)#Natural_join
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 106 | 4770 | 5 (0)| 00:00:01 |
| 1 | MERGE JOIN CARTESIAN | | 106 | 4770 | 5 (0)| 00:00:01 |
| 2 | MERGE JOIN | | 106 | 3816 | 5 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 27 | 432 | 2 (0)| 00:00:01 |
| 4 | INDEX FULL SCAN | DEPT_ID_PK | 27 | | 1 (0)| 00:00:01 |
|* 5 | SORT JOIN | | 107 | 2140 | 3 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL | EMPLOYEES | 107 | 2140 | 3 (0)| 00:00:01 |
| 7 | BUFFER SORT | | 1 | 9 | 2 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | LOC_CITY_IX | 1 | 9 | 0 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
答案 1 :(得分:1)
简短回答:不要使用NATURAL JOIN
- 它只是在惹麻烦(考虑有人重命名其中一个表中的列时的情况)。
答案很长:
这些查询可能会返回不同的结果有几个原因:
EXPLAIN PLAN
Wikipedia article about NATURAL JOIN mentioning they're dangerous