본문 바로가기

Kitri_NCS3기 보안과정/DB보안

170530 서브쿼리(SUBQUERY)를 사용한 데이터 조회

서브쿼리(SUBQUERY)는 쿼리문안에 쿼리문을 더 넣는 방법이다. SELECT문안에 다른 SELECT문이 있는 모양인데, 뽑아올 데이터가 상수화 되어있지 않았을때, 예를 들어 지빵의 봉급보다 많이받는 사원의 이름, 봉급을 알고 싶은데, 지빵의 봉급을 알고 있어야 하겟죠? 그렇기 때문에 서브쿼리문으로 지빵의 봉급을 구하고 다시 지빵의 봉급보다 많이받는 사원들의 데이터를 찾아오는 방식입니다.

 

서브쿼리를 사용할때 고려사항

1. 서브쿼리를 괄호로 감싸서 사용한다.

2. 서브쿼리는 단일 행 또는 복수행 비교연산자와 함께 사용 가능하다.

: 연산자가 단순 연산자를 사용할 경우는 서브쿼리에서 리턴되는 레코드가 하나의 행만을 리턴해야합니다.

 하나의 행이 리턴되기 위해선 데이터값이 각자 고유값을 가지고 있으면 되겟죠. 고유값하면 기본키. 기본키를 사용하는것도 하나의 방법입니다.

3. 서브쿼리는 ORDER BY를 사용할 수 없다.

: 서브쿼리는 메인쿼리에서 처리할 데이터를 먼저 뽑아서 주기 때문에 결과 레코드를 전달하는 과정에서 유효한 ORDER BY는 사용할 수 없습니다.

  사용 환경시점 자체가 다르네요. ORDER BY는 메인 쿼리의 가장 마지막에 추가 해 주도록 합시다.

 

 

Abel 의 봉급을 가지고와서 employees 들과 비교하여 더 높은사람들을 뽑아내고 있네요 메인쿼리문에서 처리하기위한 조건에 부합하는 상수값이 없을 경우 서브쿼리로 조건문에서 상수값을 도출해 메인쿼리문의 처리작업에 적용시키는걸 확인했습니다.

 

서브쿼리를 사용하는 경우 주의해야하는 경우가 서브쿼리가 메인쿼리로 던져주는 반환값이 없거나 null값을 가지고 있을경우에는

메인쿼리에서 항상 no rows selected 상태를 띄게 되는데요. null 값의 연산은 항상 null이기 때문이라고 합니다. 그렇다면 서브쿼리에서 메인쿼리로 반환값을 던져주는경우에 null이 포함된 요소를 배제 시키거나 애초에 null이 없도록 Default 값을 정해주거나 사용자의 입력의 경우에 수에 null을 대체해서 입력하는 경우를 포함시키면 될듯합니다. 여기서는 서브쿼리가 null을 배제하고 메인쿼리로 반환값을 던져주는 방식만 알아보도록 합시다.

 

NVL문을 사용해서 null을 다른 문자로 대체시켜 제외시키는 방식인데요. 결과적으로 null값을 입력시에 대체시켜주느냐 처리과정에서 대체시켜주느냐의 차이인것 같네요.

메인쿼리와 서브쿼리에서 모두 null을 잡아서 0 으로 대체시켜주는 작업을 하게 될텐데, 두번의 처리과정을 거치는것도 그렇고 데이터의 양이 많을경우에는 데이터베이스에 부하가 걸리는 단점이 있다고 합니다.

 

 

처음에 서브쿼리는 단일 행과 복수행 비교연산자와 함께 사용 가능하다고 언급했는데 복수행의 연산자를 어떻게 사용하는지 알아보겠습니다.

서브쿼리를 처리하는 다중 행 연산자에는 ANY,ALL,IN 이 있는데요.                

 ANY

 ALL

IN 

여러 값중 하나 

모든 값 

여러 값중 하나와 같다 

의 의미를 가지고 있습니다.

IN은 단독으로 사용되지만 ANY와 ALL은 단순 비교연산자와 조합이되어 사용됩니다.

 

범위상의 차이가 있는데, Where절에서 사용할 경우 어떤식으로 적용이 되는지 살펴 봅시다.

 ANY/ALL

의미 

 Column < ANY (서브쿼리)

가장 큰 값보다 작음

 Column > ANY (서브쿼리)

가장 작은 값보다 큼

 Column < ALL (서브쿼리)

가장 작은 값보다 작음

 Column < ALL (서브쿼리)

가장 큰 값보다 큼

 

예를 들어 100, 200, 300이 있을 경우 Column < ANY는 여러값중 하나보다 작다의 의미로 여러값이 모두 포함된 범위에서 작은 것을 뜻하므로 300보다 작다고 하는것 가장 큰값보다 작습니다. Column > ANY의 경우는 위와 마찬가지로 여러 값이 모두 포함된 범위에서 커야 하기 때문에 가장 작은것보다 크다고 고 하는것이겠네요. Column < ALL 은 모든 값을기준으로 비교했을 때 작은값이므로 가장 작은값보다 작고, Column >ALL은 모든 값을 기준으로 비교했을때 커야 하므로 가장 큰 값보다 크다고 볼 수 있겠습니다.

도식화 하면 위와 같이 표현 할 수 있겠습니다. 하지만 ANY와 ALL의 경우 다른 방식으로 대체하여 더 많이 사용한다고 하는데요.

단순연산자+ALL/ANY = 단순연산자+MIN/MAX로 대체하여 사용 할 수 있습니다.


서브쿼리를 전부 < ALL 을 사용 했을때와 서브쿼리 내부에서 MIN의 다중함수를 사용했을 경우의 결과값이 일치합니다. 


ALL과 ANY를 살펴 봣으니 IN을 보도록 하겠습니다. 

IN은 단독으로 사용되면서 서브쿼리와 일치하는 "="의 레코드를 뽑아주는 의미를 가지게 되는데요. 서브쿼리의 결과값이 되면서 동시에 메인쿼리의 where절의 조건을 충족하는 값들을 골라내 줍니다. 


다른 직원의 Manager가 되는 직원의 employee_id, last_name, salary를 구하는 문장입니다. 

IN을 사용함으로써 두가지 조건의 동시에만족하는 "=" 일치의 의미를 가지게 됬네요.


IN은 이런 방식으로 사용하는데 NOT이 붙으면 고려해야 할 사항이 있습니다. 

위에서 서브쿼리에서 메인쿼리로 반환값을 던져주게 되는 경우에 null이 있을 경우 no rows selected의 결과가 나온다 했는데요. 

NOT IN을 사용하면서도 같은 현상이 나타납니다.  NOT IN은 말 그대로 IN의 반대의미가 되겠죠 ? 일치의 반대에는 행이 존재하면서 데이터도 역시 있을 수도 있겠지만 행만 존재하고 데이터가 없는 경우도 있을겁니다. 이 경우에 null이 유입되기 때문에 no rows selected를 뱉어내게 되는거겠죠 ?


 

그러므로 메인쿼리의 Where 절 또는 Having 절에서 NOT IN 연산자와 서브쿼리가 같이 사용되는 경우에는 서브쿼리에서 null값을 걸러줘야 합니다. where 조건을 걸어서 IS NOT NULL을 사용해주면 됩니다.