이 쿼리는 왜 작동합니까?


37

Oracle 12c에 대해 table_a (id, name) 및 table_b (id)의 두 테이블이 있습니다.

이 쿼리가 예외를 반환하지 않는 이유는 무엇입니까?

select * from table_a where name in (select name from table_b);

내가 이해 한 바에 따르면 오라클은 이것을 다음과 같이 봅니다.

select * from table_a where name = name;

그러나 내가 얻지 못하는 것은 왜입니까?

답변:


61

table_b이없는 경우에도 쿼리는 구문 상 올바른 SQL name입니다. 그 이유는 범위 확인입니다.

쿼리를 구문 분석 할 때 먼저 열 table_b이 있는지 확인합니다 name. 그렇지 않기 때문에 table_a확인됩니다. 테이블에 name열 이없는 경우에만 오류가 발생합니다 .

마지막으로 쿼리는 다음과 같이 실행됩니다.

select a.* 
from table_a  a
where a.name in (select a.name 
                 from table_b  b
                );

결과에 대해 쿼리의 모든 행에 table_a대해 하위 쿼리 는 (select name from table_b)또는 값 (select a.name from table_b b)이 같고 a.name행이 많은 단일 열이있는 테이블입니다 table_b. 따라서 table_b하나 이상의 행이 있으면 쿼리는 다음과 같이 실행됩니다.

select a.* 
from table_a  a
where a.name in (a.name, a.name, ..., a.name) ;

또는:

select a.* 
from table_a  a
where a.name = a.name ;

또는:

select a.* 
from table_a  a
where a.name is not null ;

table_b비어 있으면 쿼리는 행을 반환하지 않습니다 (thnx에서 @ughai로 해당 가능성을 나타냄).


그것은 (오류가 발생하지 않는다는 사실) 아마 모든 열 참조에 테이블 이름 / 별칭이 접두사를 붙여야하는 가장 좋은 이유 일 것입니다. 쿼리가 다음과 같은 경우

select a.* from table_a where a.name in (select b.name from table_b); 

오류가 바로 발생했을 것입니다. 테이블 접두사가 생략되면, 특히 더 복잡한 쿼리에서 이러한 실수가 발생하는 것이 어렵지 않으며 더욱 중요한 것은 눈에 띄지 않습니다.

또한 Oracle Docs : 정적 SQL 문에서 이름 확인 내부 캡처 의 유사한 예제 B-6 및 SELECT 및 DML 문에서 내부 캡처 방지의 단락에 있는 권장 사항을 참조하십시오 .

명령문의 각 열 참조를 적절한 테이블 별명으로 규정하십시오.


SQL 엔진의 내부 작업을 어떻게 정확하게 분석 했습니까?
RinkyPinku

8

때문에

중첩 된 하위 쿼리가 하위 쿼리보다 한 수준 위의 부모 문을 참조하는 테이블의 열을 참조하면 Oracle은 상관 된 하위 쿼리를 수행합니다. http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

하위 쿼리가 상호 관련되어 있는지 여부를 확인 하려면 Oracle 외부 문 컨텍스트를 포함하여 하위 쿼리에서 이름을 확인 해야합니다 . 그리고 접두사가없는 name경우 가능한 유일한 해결책입니다.


4

더 없다 name필드 table_b오라클에서 일을합니다 그래서는 table_a. 나는 시도 EXPLAIN PLAN했지만 이것은 나에게만 있다고 말했다 TABLE ACCESS FULL. 나는 이것이 두 테이블 사이에 어떤 종류의 카티 전 곱을 생성한다고 가정하고 모든 이름의 목록 table_a이 하위 쿼리에 의해 반환 된다고 가정 합니다.


5
"table_b에는 이름 필드가 없으므로 Oracle은 table_a에서 이름 필드를 가져옵니다." 옳은. "나는 이것이 일종의 카티 전 곱을 생성 할 것이라고 추정한다." 잘못된. 검색어에가 from table_a where ...있습니다. 널인 행을 table_a제외한 모든 행을 리턴합니다 name.
ypercubeᵀᴹ

1
TABLE ACCESS FULL순차 스캔을 수행하고 있음을 알리는 오라클의 방법입니다.
Joishi Bodio 2016

1
귀하의 계획은 무의미합니다-거대한 테이블로 인덱싱하는 것이 좋을 수도 있습니다. 테스트 데이터를 실행한다고 가정하고 있습니까?
Vérace 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.