앞서 부서별로 직원 수를 구하는 문제를
3가지 방법으로 살펴 보았다.
조인(Join) 4번, 하위쿼리(SubQuery)에서 1번과 4번 문제로
정리하는 의미에서
부서 이동 문제를 이용하여 다음과 같이 정리하였다.
실습 2 - GROUP의 6번 문제에서
[다음 그림과 같이 직원들의 부서 이동 과정을 출력하시오] 라는 문제를 풀었다.
SELECT DE.EMP_NO, GROUP_CONCAT(DE.DEPT_NO SEPARATOR ' > ' ) PATH
FROM DEPT_EMP DE
GROUP BY DE.EMP_NO
HAVING COUNT(*)>1
ORDER BY COUNT(*) DESC;
이 문제는 좀 더 많은 설명과 구현이 필요한 SQL문이다.
먼저, 다음 그림과 같이 실행 결과에서 직원의 이름과 부서 명이 필요하다.
(아래의 설명을 읽는 것도 좋겠지만
위와 같이 출력되게 하는 SQL문을 직접 작성해 보면 실력향상에 도움이 될 것이다.)
SELECT DE.EMP_NO, E.FIRST_NAME, E.LAST_NAME, GROUP_CONCAT(D.DEPT_NAME SEPARATOR ' > ' ) PATH
FROM DEPT_EMP DE
INNER JOIN DEPARTMENTS D ON D.DEPT_NO=DE.DEPT_NO
INNER JOIN EMPLOYEES E ON E.EMP_NO=DE.EMP_NO
GROUP BY DE.EMP_NO, E.FIRST_NAME, E.LAST_NAME
HAVING COUNT(*)>1
ORDER BY COUNT(*) DESC;
직원의 이름(FIRST_NAME, LAST_NAME)과
부서 명(DEPT_NAME)이 출력되기 위해서는
직원 테이블(EMPLOYEES)과 부서 테이블(DEPARTMENTS)을 추가해 주면 된다.
그리고, 직원 정보로 GROUP화하고
부서 명(DEPT_NAME)을 묶으면 된다.
여기서 생각해야 할 것이 GROUP으로 직원 정보를 사용하는 것이다.
직원명외에 생일을 추가한다고 할 경우
GROUP에 생일 필드를 추가해야 한다.
GROUP에 가변길이 문자열을 많은 추가하는 것은
SQL 성능(속도)상 추천되지 않는다.
다음과 같이 하위쿼리(SubQuery)를 이용하는 것이 바람직하다.
SELECT DS.EMP_NO, E.FIRST_NAME, E.LAST_NAME, PATH
FROM (
SELECT DE.EMP_NO, GROUP_CONCAT(D.DEPT_NAME SEPARATOR ' > ' ) PATH, COUNT(*) CNT
FROM DEPT_EMP DE
INNER JOIN DEPARTMENTS D ON D.DEPT_NO=DE.DEPT_NO
GROUP BY DE.EMP_NO
HAVING COUNT(*)>1
) DS
INNER JOIN EMPLOYEES E ON E.EMP_NO=DS.EMP_NO
ORDER BY CNT DESC;
부서는 조인을 이용하지만
개인정보는 하위쿼리를 사용하는 것이 좋다.
GROUP에 사용된 다는 것은 인덱스가 필요하다는 의미로
좀 더 복잡한 처리가 필요한 것도 있지만,
단순하게 데이터 개수의 의미도 있다.
조인을 사용할 경우
직원 수가 약 30만(300,024)이고,
부서 할당 정보가 약 33만 (331,603)이니
30만 * 33만의 처리가 발생한다.
하위 쿼리로 실행하면,
다음 SQL에서 알수 있듯이
처리 개수가 3만(31,579)개로 줄어든다.
부서 이동이 발생한 직원들만 처리하기 때문이며,
당연이 조인시 발생하는 처리 수도 줄어 든다.
SELECT COUNT(*)
FROM (
SELECT DE.EMP_NO, GROUP_CONCAT(D.DEPT_NAME SEPARATOR ' > ' ) PATH, COUNT(*) CNT
FROM DEPT_EMP DE
INNER JOIN DEPARTMENTS D ON D.DEPT_NO=DE.DEPT_NO
GROUP BY DE.EMP_NO
HAVING COUNT(*)>1
) DS
제대로 완성 시키려면,
현재 근무하는 직원만 출력해야 한다.
현재 근무하는 직원은
부서 할당(DEPT_EMP) 테이블에
근무 종료(TO_DATE)가 9999-01-01인 직원들이므로
다음과 같이 두개의 부서 할당 테이블이 필요하다.
하나는 현재 근무 중인 직원을 가져오는 테이블(DEPT_EMP DE1),
나머지는 부서 이동 정보를 가져오는 테이블(DEPT_EMP DE2)이다.
SELECT DS.EMP_NO, E.FIRST_NAME, E.LAST_NAME, PATH
FROM (
SELECT DE1.EMP_NO, GROUP_CONCAT(D.DEPT_NAME SEPARATOR ' > ') PATH, COUNT(*) CNT
FROM DEPT_EMP DE1
INNER JOIN DEPT_EMP DE2 ON DE2.EMP_NO=DE1.EMP_NO
INNER JOIN DEPARTMENTS D ON D.DEPT_NO=DE2.DEPT_NO
WHERE DE1.TO_DATE='9999-01-01'
GROUP BY DE1.EMP_NO
HAVING COUNT(*)>1
) DS
INNER JOIN EMPLOYEES E ON E.EMP_NO=DS.EMP_NO
ORDER BY CNT DESC;
부서 테이블과의 조인은(D.DEPT_NO=DE2.DEPT_NO)
부서 이동 정보를 가져오는 테이블(DEPT_EMP DE2)이다.
'Database > SQL 연습' 카테고리의 다른 글
실습 2 - GROUP (2) | 2016.04.02 |
---|---|
실습 3 - Join (0) | 2016.04.02 |
실습 4 - SubQuery (0) | 2016.04.02 |
연습 1 (3) | 2016.04.02 |
연습 2 (0) | 2016.04.02 |