본문 바로가기

Archived(CSE Programming)/SQL(Oracle)

SQL_SET_SubQuery

# SET operator 

UNION / UNION ALL : 차이는 중복 결과 1번 출력 / 모두 출력

INTERSECT : 양쪽 쿼리 결과에 모두 포함되는 행만 표현

MINUS : 쿼리 결과 1에는 포함되지만 쿼리 결과 2에는 포함되지 않는 결과만

-- 기본적인 SET
SELECT		DEPT_ID
FROM		EMPLOYEE
UNION
SELECT		DEPT_ID
FROM		DEPARTMENT;
-- 더미 데이터 NULL 활용하기
SELECT		EMP_NAME
	      , JOB_ID
	      , DEPT_ID
FROM		EMPLOYEE 
UNION
SELECT		NULL
	      , NULL
	      , DEPT_ID
FROM		DEPARTMENT
-- 특정 값 넣기
SELECT 		EMP_ID
	      , EMP_NAME
	      , '관리자' AS 구분
FROM		EMPLOYEE
WHERE		EMP_ID = '141'
AND		DEPT_ID = '50';
UNION
SELECT 		EMP_ID
	      , EMP_NAME
	      , '직원' AS 구분
FROM		EMPLOYEE
WHERE		DEPT_ID = '50'
AND		EMP_ID != '141';
ORDER BY	3, 1;

반드시 UNION을 안쓰더라도 IN 을 통해 같은 효과를 낼 수 있는 경우도 있다!

-- IN 활용
SELECT		EMP_NAME
	      ,	JOB_TITLE 직급
FROM		EMPLOYEE
JOIN		JOB USING (JOB_ID)
WHERE		JOB_TITLE IN ('대리', '사원')
ORDER BY 	2,1

-- UNION 활용
SELECT		EMP_NAME, '사원' 직급
FROM		EMPLOYEE
JOIN		JOB USING (JOB_ID)
WHERE		JOB_TITLE = '대리'
UNION
SELECT		EMP_NAME , '대리' 직급
FROM		EMPLOYEE
JOIN		JOB USING (JOB_ID)
WHERE		JOB_TITLE = '대리'
ORDER BY 	2,1;

# SubQuery

하나의 쿼리가 다른 쿼리에 포함되는 구조

다른 쿼리에 포함된 내부 쿼리(서브 쿼리)는 외부 쿼리(메인 쿼리)에 사용될 값을 반환하는 역할

 

# 단일 행 서브 쿼리

단일 행 반환 / 단일 행 비교 연산자 사용

 

# 다중 행 서브 쿼리

여러 행 반환 / 다중 행 비교 연산자 사용

SELECT		EMP_NAME
	      , JOB_ID
	      , SALARY
FROM		EMPLOYEE
WHERE		JOB_ID = (SELECT 	JOB_ID
			  FROM		EMPLOYEE
			  WHERE		EMP_NAME = '나승원')
AND		SALARY > (SELECT 	SALARY
			  FROM		EMPLOYEE
			  WHERE		EMP_NAME = '나승원');
-- SUB QUERY
SELECT		EMP_NAME
	      , JOB_ID
	      , SALARY
FROM		EMPLOYEE
WHERE		SALARY = (SELECT MIN(SALARY)
			  FROM	 EMPLOYEE);
-- Sub Query
SELECT		DEPT_NAME
	      , SUM(SALARY)
FROM		EMPLOYEE
LEFT JOIN	DEPARTMENT USING(DEPT_ID)
GROUP BY 	DEPT_ID, DEPT_NAME
HAVING		SUM(SALARY) = (SELECT 	MAX(SUM(SALARY))
                               FROM		EMPLOYEE
                               GROUP BY	DEPT_ID);
-- 부서마다 최소 연봉과 동일한 연봉 지닌 사람들
SELECT		EMP_ID
	      , EMP_NAME
FROM		EMPLOYEE
WHERE		SALARY IN (SELECT 	MIN(SALARY)
                           FROM		EMPLOYEE
                           GROUP BY	DEPT_ID);
                           
-- 부서마다 최소 연봉 찾기
SELECT		EMP_ID
	      , EMP_NAME
FROM		EMPLOYEE
WHERE		(SALARY, DEPT_ID) IN (SELECT 	MIN(SALARY), DEPT_ID
                                      FROM		EMPLOYEE
                                      GROUP BY	DEPT_ID)	

SUB QUERY를 먼저 구성하고 결과를 살펴본 다음에 어떻게 맵핑 또는 비교를 할지를 판단하기

섣부르게 MAIN QUERY 먼저 접근하지 않기

CF. SUB QUERY에 대해 NOT IN을 쓸 거면 NULL 값이 있는지 없는지 고려하기

-- SUB QUERY
SELECT		EMP_ID
	      , EMP_NAME
	      , '관리자' AS 구분
FROM		EMPLOYEE
WHERE		EMP_ID IN (SELECT MGR_ID FROM EMPLOYEE)
UNION
SELECT		EMP_ID
	      , EMP_NAME
	      , '직원'
FROM		EMPLOYEE
WHERE		EMP_ID NOT IN(SELECT MGR_ID FROM EMPLOYEE
                              WHERE	 MGR_ID IS NOT NULL)
ORDER BY	3, 1;

IN / ANY 는 범위 조회에 많이 활용됨

< ANY : 비교 대상 중 최대 값 보다 작음

> ANY : 비교 대상 중 최소 값 보다 큼

ANY를 사용하게 되면 어떤 하나라도 가능(박스 안에서 비교하는 것)

-- ANY 어떤 한 과장 직급보다 많이 받는 대리 들
SELECT		EMP_NAME
	      , SALARY
FROM		EMPLOYEE
JOIN		JOB USING(JOB_ID)
WHERE		JOB_TITLE = '대리'
AND		SALARY > ANY(SELECT SALARY
                             FROM	EMPLOYEE
                             JOIN	JOB USING(JOB_ID)
                             WHERE	JOB_TITLE = '과장')

CF. FROM 절에 사용하면 INLINE VIEW / SELECT에 쓰면 SCALAR QUERY

INLINE VIEW 활용

-- 직급별 평균급여 조회
-- 에 해당하는 직원 정보 조회
SELECT		E.EMP_NAME
	      , J.JOB_TITLE
	      , E.SALARY
FROM		(SELECT 		JOB_ID
               			      , TRUNC(AVG(SALARY), -5) JOBAVG
                FROM			EMPLOYEE
                GROUP BY		JOB_ID) V
JOIN		EMPLOYEE E ON(E.SALARY = V.JOBAVG AND E.JOB_ID = V.JOB_ID)
JOIN		JOB J ON(J.JOB_ID = E.JOB_ID)

# EXISTS, NOT EXISTS 둘 다 사용 가능

CF. SUB QUERY는 DB 성능에 치명적인 부분이므로 최대한으로 어떻게 처리할 지 고민해보기!

상황마다 일반 서브 쿼리, INLINE VIEW, SCALAR SUB QUERY 성능 고려해보기

'Archived(CSE Programming) > SQL(Oracle)' 카테고리의 다른 글

SQL_DML  (0) 2020.01.29
SQL_DDL  (0) 2020.01.23
SQL_JOIN  (0) 2020.01.21
SQL_Additional_SELECT_그룹 함수  (0) 2020.01.21
SQL_Additional_SELECT_단일 행 함수  (0) 2020.01.20