1

我执行了一条 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

4 回答 4

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

于 2013-10-22T10:42:30.760 回答
0

如果您运行此查询:

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

您将在查询中看到错误 dept_no 来自员工表(而不是来自 dep1 表),当 dept_no 为 null 时,将不会返回任何结果,如果您将 dept_name 更改为不在 dep1 表中的内容很明显,您的 dep1 表没有返回任何内容,然后 dept_no 不能什么都没有。

于 2013-10-22T10:45:58.840 回答
0

让我试着回答一下。

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

让我来看看你的案子。以下是您查询的解释计划

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 和存在的更多信息。

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

询问:

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 查询解析器和优化器。

于 2013-10-22T12:18:16.200 回答
-1

加盟怎么样?

select a.emp_name
  from employee a
  join dep1 b
    on a.dept_no = b.dept_id
 where b.dept_name = 'MEC'
于 2013-10-22T10:26:01.867 回答