了解Oracle 10g中的多行子查询

时间:2013-10-22 10:07:38

标签: oracle

我执行了一个SQL语句并遇到了麻烦。我无法理解这个输出是如何产生的。 我的员工表是:Emp_Id是主键,dept_no是其他表的外键。

EMP_ID     EMP_NAME             DEPT_NO    MGR_NAME      MGR_NO
---------- -------------------- ---------- ---------- -----------
       111 Anish                       121 Tanuj            1123
       112 Aman                        122 Jasmeet          1234
      1123 Tanuj                       122 Vipul             122
      1234 Jasmeet                     122 Anish             111
       122 Vipul                       123 Aman              112
       100 Chetan                      123 Anoop             666
       101 Antal                           Aman
      1011 Anjali                      126
      1111 Angelina                    127

我的dep1表是:

   DEPT_ID DEPT_NAME
---------- -------------
       121 CSE
       122 ECE
       123 MEC

这两张表根本没有关联。

SQL查询是:

SQL> select emp_name 
     from employee 
     where dept_no IN (select dept_no from dep1 where dept_name='MEC'); 

输出是:

EMP_NAME 
-------------------- 
Anish 
Aman
Tanuj 
Jasmeet 
Vipul 
Chetan 
Anjali 
Angelina  
8 rows selected.

如果我将where条件更改为dept_name ='me',则不返回任何行。 有人可以解释为什么执行没有产生错误,因为dept_no不是dep1表的列。以及如何生成输出。

4 个答案:

答案 0 :(得分:0)

从您的查询开始,

..where dept_no IN (select dept_no ...); -- it is similar as using EXISTS

条件EXISTS在这里完成:( oracle不会为EXISTS子句返回错误。)

CREATE TABLE my_test(ID INT);
CREATE TABLE my_new_test ( new_ID INT);
EXPLAIN PLAN FOR 
select * from my_test where id in( select id from my_new_test);

select * from table(dbms_xplan.display);

-----------------------------------------------------------------------------------                                                                                                                                                                                                                          
| Id  | Operation           | Name        | Rows  | Bytes | Cost (%CPU)| Time     |                                                                                                                                                                                                                          
-----------------------------------------------------------------------------------                                                                                                                                                                                                                          
|   0 | SELECT STATEMENT    |             |     1 |    13 |     4   (0)| 00:00:01 |                                                                                                                                                                                                                          
|*  1 |  FILTER             |             |       |       |            |          |                                                                                                                                                                                                                          
|   2 |   TABLE ACCESS FULL | MY_TEST     |     1 |    13 |     2   (0)| 00:00:01 |                                                                                                                                                                                                                          
|*  3 |   FILTER            |             |       |       |            |          |                                                                                                                                                                                                                          
|   4 |    TABLE ACCESS FULL| MY_NEW_TEST |     1 |       |     2   (0)| 00:00:01 |                                                                                                                                                                                                                          
-----------------------------------------------------------------------------------                                                                                                                                                                                                                          

Predicate Information (identified by operation id):                                                                                                                                                                                                                                                          
---------------------------------------------------                                                                                                                                                                                                                                                          

   1 - filter( EXISTS (SELECT 0 FROM "MY_NEW_TEST" "MY_NEW_TEST" WHERE                                                                                                                                                                                                                                       
              :B1=:B2))                                                                                                                                                                                                                                                                                      
   3 - filter(:B1=:B2)                                                                                                                                                                                                                                                                                       

Note                                                                                                                                                                                                                                                                                                         
-----                                                                                                                                                                                                                                                                                                        
   - dynamic sampling used for this statement (level=2)  

如果您执行有效列的计划,请在此处(new_id): 然后进行正常访问:

  1 - ACCESS("ID"="NEW_ID")

以下将导致错误:

EXPLAIN PLAN FOR 
select * from my_test where id in( select some_thing from my_new_test);

SQL Error: ORA-00904: "SOME_THING": invalid identifier

答案 1 :(得分:0)

如果您运行此查询:

 select emp_name 
 from employee 
 where dept_no IN (select t.dept_no from dep1 t where dept_name='MEC'); 

你会在你的查询中看到错误dept_no来自employee表(不是来自dep1表),当dept_no为null时,没有结果将从它返回,如果你将dept_name更改为不在dep1表很清楚你的dep1表什么都没有返回,然后dept_no就什么都不能。

答案 2 :(得分:0)

让我试着回答一下。

Oracle使用优化程序来决定解释计划。 Oracle可能会根据需要重写您的查询,并认为哪个更好。并且存在和可存在是可互换的,性能取决于不同的东西。 (存在以全表扫描和使用索引结束)。

让我谈谈你的情况。以下是您的查询的解释计划

Plan hash value: 3333342911

----------------------------------------------------------------------------------
| Id  | Operation           | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |            |     9 |   225 |     6   (0)| 00:00:01 |
|*  1 |  FILTER             |            |       |       |            |          |
|   2 |   TABLE ACCESS FULL | EMPLOYEE   |     9 |   225 |     3   (0)| 00:00:01 |
|*  3 |   FILTER            |            |       |       |            |          |
|*  4 |    TABLE ACCESS FULL| DEPARTMENT |     1 |    12 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter( EXISTS (SELECT 0 FROM "DEPARTMENT" "DEPARTMENT" WHERE 
          :B1=:B2 AND "DEPT_NAME"='MEC'))
3 - filter(:B1=:B2)
4 - filter("DEPT_NAME"='MEC')

Note
-----
- dynamic sampling used for this statement (level=2)

此解释计划清楚地表明查询被重写为使用存在,它等同于

select emp_name from employee where exists (select 0 from department where dept_name = 'MEC' and dept_no = dept_no);

上述查询是一个有效的查询,您将获得正确的结果。

绑定变量只不过是dept_no(连接列)。

请参阅此IN vs EXISTS in oracle链接,了解有关in和exists的更多信息。

如果使用正确的列名,则说明计划完全不同。以下是查询和解释计划

查询:

select emp_name from employee where dept_no IN (select dept_id from department where dept_name='MEC');

解释计划:

Plan hash value: 3817251802

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |     2 |   100 |     7  (15)| 00:00:01 |
|*  1 |  HASH JOIN SEMI    |            |     2 |   100 |     7  (15)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMPLOYEE   |     9 |   225 |     3   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| DEPARTMENT |     1 |    25 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("DEPT_NO"="DEPT_ID")
3 - filter("DEPT_NAME"='MEC')

Note
-----
- dynamic sampling used for this statement (level=2)

Oracle认为最好使用过滤器和散列连接来获取所需的详细信息。

此行为取决于oracle查询解析器和优化程序。

答案 3 :(得分:-1)

加入怎么样?

select a.emp_name
  from employee a
  join dep1 b
    on a.dept_no = b.dept_id
 where b.dept_name = 'MEC'