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
로 쓰면, 대응되는 행이 없을 때 해당 행을 반환하지 않는다(+)
기호를 붙여주면, 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 -)은 반환되지 않는다.
NULL
사용하기NULL
은 그 자신을 제외한 어떤 값과도 같거나 같지 않다.(비교 연산 불가능)
NULL
이 허용된 열에서 반환값을 평가하기말이 어렵다.
예를 들어, 커미션(칼럼 'COMM')이 특정사원의 커미션보다 적은 모든 사원명을 'EMP'테이블에서 찾으려고 한다.
이 때, 커미션이 더 적다는 범위에 NULL
도 넣으려고 한다는 말이다.
NULL
은 0도 아니고 그냥 존재하지 않는다는 의미인데, 이걸 0으로 치겠다는 말과 같다.
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.
정답!
굉장히 길었다.
JOIN
으로 할 수 있는 복합한 쿼리는 다 본 느낌이다.
OUTER JOIN
과 UNION
을 사용한 해법이 가장 통쾌(?)했다.
제3. 4~5 장
다른 테이블에 존재하지 않는 '값' 또는 '행' 구하기가 가장 어려웠다
IN
의 연산이 본질적으로 OR
연산이라는 것은 알겠는데 쿼리는 헷갈린다
제3. 6 장
스칼라 서브쿼리라는 생소한 말이 나왔다
아직까지 하나도 익숙하지 않다 너무 어색하다
자주 확인해도 친해지지 않을 것 같다
그래도 자주 확인할 것이다
제3. 7~9 장
그룹 함수에서도 약점이 크게 드러났다
GROUP BY
를 사용했을 때 칼럼 구조가 어떻게 되는지 바로 생각나지 않는다
over (partition by ...)
로 떼운 느낌인데 모든 게 처음이라 익숙한 것이 없다
한계를 많이 느끼고 있다.
원인은 사실 명확하다.
기초 체력이 너무 약하다.
잠시 현업에 종사했을 때도 주로 JOIN
만을 사용했다.
문자열∙날짜처리 등 정말로 중요한 부분은 제대로 익히지 않고 구글링에 의지했다.
그 때문에 기초가 아예 없다는 기분이 든다.
조금만 생각해야 하는 문제가 나오면 머릿속에 백지장만 가득했다.
이 두꺼운 책의 한장한장을 보면서 따라하고, 어느새 100페이지를 넘겼는데 아무 것도 남지 않은 것 같다.
본격적으로 배우고 싶던 문자열 작업(제 6장)에 들어가기 전까지 천천히 가자.
천천히 가야겠다. 뒤도 돌아보면서 가야겠다.
쿼리는 필요할 때 찾아서 쓰면 그만이라는 말이 있다.
이런 말 때문에 실력의 격차가 확실한 것 같다.
나는 django ORM을 통해 아주 가볍게, 쉽게 DB에 입문했다.
그리고 현업을 거치면서 이게 얼마나 골치 아프고, 잘하기 위해 얼마나 노력을 많이 해야 하는지 알면서도 쿼리를 너무 가볍게 여기지 않았나 하는 생각이 든다.
나는 아무 것도 모른다. 아무 것도 아니다. 천천히 해야겠다.