SQL Cook: 3. 12장 연산 및 비교에서 NULL 사용하기

0

SQL_COOK

목록 보기
25/35
post-thumbnail

3.11장 Oracle에 특화된 OUTER JOIN 구문

제3. 10장 '여러 테이블에서 누락된 데이터 반환하기' 문제를 해결할 수 있는 Oracle에 특화된 외부 조인 구문이 있다.

/* ORACLE */
select d.deptno, d.dname, e.ename
	from dept d, emp e
    where d.deptno = e.deptno(+)
union
select d.deptno, d.dname, e.ename
	from dept d, emp e
    where d.deptno(+) = e.deptno
>>
DEPTNO	DNAME		ENAME
10		ACCOUNTING	CLARK
10		ACCOUNTING	KING
10		ACCOUNTING	MILLER
20		RESEARCH	ADAMS
20		RESEARCH	FORD
20		RESEARCH	JONES
20		RESEARCH	SCOTT
20		RESEARCH	SMITH
30		SALES		ALLEN
30		SALES		BLAKE
30		SALES		JAMES
30		SALES		MARTIN
30		SALES		TURNER
30		SALES		WARD
40		OPERATIONS	 - 
 - 	 		- 		yoda
6 rows selected.
  • 행이 모자라는 쪽에 (+)를 붙여준다
  • d.deptno = e.deptno로 쓰면, 대응되는 행이 없을 때 해당 행을 반환하지 않는다
    예를 들어
    'EMP' 테이블의 'DEPTNO' 칼럼에는 40이라는 값이 없고, 'DEPT' 테이블의 'DEPTNO' 칼럼에는 40이라는 값이 있다고 하면
    'DEPT' 테이블의 'DEPTNO=40'에 대응하는 'EMP' 행이 존재하지 않기 때문에 'DEPTNO=40'에 대한 행은 반환조차 되지 않는다는 것이다
  • 이 때 대응되는 값을 얻을 수 없는 'DEPT' 테이블의 'DEPTNO' 칼럼에 (+)기호를 붙여주면, OUTER JOIN과 같은 효과를 볼 수 있다
    대응되는 값이 있든 없든, 상대 테이블의 행길이에 맞춰서 행을 반환하기 때문이다

쿼리를 따로 놓고 보면 아래와 같다.

/* ORACLE */
select d.deptno, d.dname, e.ename
	from dept d, emp e
    where d.deptno = e.deptno(+);
>>
DEPTNO	DNAME		ENAME
10		ACCOUNTING	KING
30		SALES		BLAKE
10		ACCOUNTING	CLARK
20		RESEARCH	JONES
20		RESEARCH	SCOTT
20		RESEARCH	FORD
20		RESEARCH	SMITH
30		SALES		ALLEN
30		SALES		WARD
30		SALES		MARTIN
30		SALES		TURNER
20		RESEARCH	ADAMS
30		SALES		JAMES
10		ACCOUNTING	MILLER
40		OPERATIONS	 - 
15 rows selected.

(+)를 빼면, 대응값이 없는 마지막 행(40 OPERATION -)은 반환되지 않는다.


제3. 12장: 연산 및 비교에서 NULL 사용하기


NULL은 그 자신을 제외한 어떤 값과도 같거나 같지 않다.(비교 연산 불가능)

Q. 실제 존재하는 값을 평가하는 것처럼NULL이 허용된 열에서 반환값을 평가하기

말이 어렵다.
예를 들어, 커미션(칼럼 'COMM')이 특정사원의 커미션보다 적은 모든 사원명을 'EMP'테이블에서 찾으려고 한다.
이 때, 커미션이 더 적다는 범위에 NULL도 넣으려고 한다는 말이다.

NULL은 0도 아니고 그냥 존재하지 않는다는 의미인데, 이걸 0으로 치겠다는 말과 같다.

A. COALESCE와 같은 함수를 사용하여, NULL값을 표준 평가에서 사용할 수 있는 실젯값으로 변환한다

굉장히 뻔한 해답인데 COALESCE를 당연하게도 까먹었다.
공부하는 의미가 점점 사라지는 느낌이다...

/* ORACLE */
select ename, comm
	from emp
    where coalesce(comm, 0) < (
    							select comm
                                	from emp
                                    where ename = 'WARD')
>>
ENAME	COMM
KING	 - 
BLAKE	 - 
CLARK	 - 
JONES	 - 
SCOTT	 - 
FORD	 - 
SMITH	 - 
ALLEN	300
TURNER	0
ADAMS	 - 
JAMES	 - 
MILLER	 - 
12 rows selected.
  • COALESCE(칼럼, NULL을 대체할 값)
    여기서는 'COMM' 칼럼의 NULL을 정수 0으로 변환했다

  • FROM절에서 'EMP' 테이블 전체를 불러온 상태에서 WHERE절의 조건 검사에 들어간다

  • WHERE절에 서브쿼리가 있고 조건 비교를 위해 서브쿼리가 실행된다

  • 사원명 'WARD'에 해당하는 'COMM'값이 반환되고

  • 외부 쿼리의 WHERE절에서 조건을 검사하여 FROM절에서 불러온 'EMP' 테이블에서 어떤 행을 반환할 것인지를 제한한다

'WARD'보다 커미션을 적게 받는 인원은 12명으로 나타났다.
검증을 위해 더 많이 받는 인원을 알아보겠다.

/* ORACLE */
select ename, comm
	from emp
    where coalesce(comm, 0) > (
    							select comm
                                	from emp
                                    where ename = 'WARD')
>>
ENAME	COMM
WARD	500
MARTIN	1400
yoda	20000
3 rows selected.

총원 15명으로 나온다.

select '-' from emp;
>>
'-'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
15 rows selected.

정답!


정리: 3장 종료

굉장히 길었다.
JOIN으로 할 수 있는 복합한 쿼리는 다 본 느낌이다.
OUTER JOINUNION을 사용한 해법이 가장 통쾌(?)했다.

  • 제3. 4~5 장
    다른 테이블에 존재하지 않는 '값' 또는 '행' 구하기가 가장 어려웠다
    IN의 연산이 본질적으로 OR연산이라는 것은 알겠는데 쿼리는 헷갈린다

  • 제3. 6 장
    스칼라 서브쿼리라는 생소한 말이 나왔다
    아직까지 하나도 익숙하지 않다 너무 어색하다
    자주 확인해도 친해지지 않을 것 같다
    그래도 자주 확인할 것이다

  • 제3. 7~9 장
    그룹 함수에서도 약점이 크게 드러났다
    GROUP BY를 사용했을 때 칼럼 구조가 어떻게 되는지 바로 생각나지 않는다

  • over (partition by ...)로 떼운 느낌인데 모든 게 처음이라 익숙한 것이 없다

한계를 많이 느끼고 있다.
원인은 사실 명확하다.
기초 체력이 너무 약하다.

잠시 현업에 종사했을 때도 주로 JOIN만을 사용했다.
문자열∙날짜처리 등 정말로 중요한 부분은 제대로 익히지 않고 구글링에 의지했다.
그 때문에 기초가 아예 없다는 기분이 든다.
조금만 생각해야 하는 문제가 나오면 머릿속에 백지장만 가득했다.

이 두꺼운 책의 한장한장을 보면서 따라하고, 어느새 100페이지를 넘겼는데 아무 것도 남지 않은 것 같다.

본격적으로 배우고 싶던 문자열 작업(제 6장)에 들어가기 전까지 천천히 가자.
천천히 가야겠다. 뒤도 돌아보면서 가야겠다.

쿼리는 필요할 때 찾아서 쓰면 그만이라는 말이 있다.

이런 말 때문에 실력의 격차가 확실한 것 같다.
나는 django ORM을 통해 아주 가볍게, 쉽게 DB에 입문했다.
그리고 현업을 거치면서 이게 얼마나 골치 아프고, 잘하기 위해 얼마나 노력을 많이 해야 하는지 알면서도 쿼리를 너무 가볍게 여기지 않았나 하는 생각이 든다.

나는 아무 것도 모른다. 아무 것도 아니다. 천천히 해야겠다.

0개의 댓글