Oracle SQL - 减少所选属性的数量会更改结果

时间:2014-06-18 08:35:42

标签: sql oracle

我正在玩连接并发现这个奇怪的问题:

我试过这样的事情:

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。

谢谢

2 个答案:

答案 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 - 它只是在惹麻烦(考虑有人重命名其中一个表中的列时的情况)。

答案很长:

这些查询可能会返回不同的结果有几个原因:

  • 其中一个可能使用Query Rewrite(如果存在符合条件的物化视图);检查两个查询的EXPLAIN PLAN
  • 您可能会遇到Oracle错误;你没有提到你正在运行的版本/补丁级别,所以很难说清楚,请参阅下面的可能候选人的简短列表

Wikipedia article about NATURAL JOIN mentioning they're dangerous

WRONG RESULTS bug, referencing Metalink #406966.1

Oracle forum discussion on buggy NATURAL JOINs