[문제] 최고 급여를 받는 사원의 정보, 부서 이름 정보를 출력해주세요. |
1) SUBQUERY, INLINE VIEW, JOIN SELECT * FROM hr.employees e JOIN hr.departments d ON e.department_id = d.department_id WHERE salary = (SELECT max(salary) FROM hr.employees); # SUBQUERY SELECT * FROM hr.employees WHERE salary = 최고급여; -- WHERE절 : 행제한, 행추출, 그룹함수X + SELECT max(salary) FROM hr.employees; || SELECT * FROM hr.employees WHERE salary = (SELECT max(salary) FROM hr.employees); -> 최고급여를 받는 사원정보 ↓ # INLINE VIEW = 가상테이블로 만들기 SELECT * FROM (SELECT * FROM hr.employees WHERE salary = (SELECT max(salary) FROM hr.employees)); ↓ # JOIN = 부서테이블과 연결 SELECT * FROM (SELECT * FROM hr.employees WHERE salary = (SELECT max(salary) FROM hr.employees)) e, hr.departments d WHERE e.department_id = d.department_id; |
2) SUBQUERY, SCALAR SUBQUERY # SUBQUERY SELECT * FROM hr.employees WHERE salary = (SELECT max(salary) FROM hr.employees); + # SCALAR SUBQUERY 조인을 하지않고 묶기 SELECT e.*, 부서이름 FROM hr.employees e WHERE salary = (SELECT max(salary) FROM hr.employees); + SELECT department_name FROM hr.departments WHERE department_id = e.department_id; -- 단일행, 단일값 ↓ SELECT e.*, (SELECT department_name -- SELECT에 입력 FROM hr.departments WHERE department_id = e.department_id) dept_name FROM hr.employees e WHERE salary = (SELECT max(salary) FROM hr.employees); |
■ 집합연산자
- UNION, UNION ALL, INTERSECT, MINUS
합집합 교집합 차집합
- SELECT 절의 컬럼의 갯수가 일치해야 한다.
- 첫번째 SELECT 절에 대응되는 두번째 SELECT 절 컬럼의 데이터 타입이 일치해야한다.
- UNION, INTERSECT, MINUS 연산자는 중복을 제거한다.(내부적으로 정렬이 발생한다.)
- UNION ALL 연산자는 중복되는 데이터도 포함하기 때문에 내부적으로 정렬이 발생하지 않는다.
- 집합연산자에서 ORDER BY 절은 제일 마지막에 작성해야 한다.
- ORDER BY 절에는 첫번째 SELECT 절의 컬럼이름, 별칭, 위치표기법을 사용한다.
1. 합집합
- UNION : 중복을 제거
- UNION ALL : 중복을 포함
SELECT employee_id, job_id, salary
FROM hr.employees;
+
SELECT employee_id, job_id
FROM hr.job_history;
↓
SELECT employee_id, job_id, salary
FROM hr.employees
UNION
SELECT employee_id, job_id, NULL
FROM hr.job_history; -- 정렬 -> 중복제외
SELECT employee_id, job_id, salary -- salary 숫자형
FROM hr.employees
UNION
SELECT employee_id, job_id, 0 -- 0 숫자형
FROM hr.job_history;
SELECT employee_id, job_id, salary -- salary 숫자형
FROM hr.employees
UNION
SELECT employee_id, job_id, '무급' -- '무급' 문자형
FROM hr.job_history; --> 오류, 데이터 타입 불일치
↓
SELECT employee_id, job_id, to_char(salary) -- to_char(salary) 문자형
FROM hr.employees
UNION
SELECT employee_id, job_id, '무급' -- '무급' 문자형
FROM hr.job_history;
SELECT employee_id as id, job_id job, to_char(salary) sal -- 상위 칼럼명을 기준으로 노출
FROM hr.employees
UNION
SELECT employee_id, job_id, '무급'
FROM hr.job_history;
SELECT employee_id
FROM hr.employees
UNION -- 107행, 중복 제외
SELECT employee_id
FROM hr.job_history;
SELECT employee_id
FROM hr.employees
UNION ALL -- 117행, 중복 포함, 정렬X
SELECT employee_id
FROM hr.job_history;
↓
SELECT employee_id id
FROM hr.employees
UNION ALL -- 117행, 중복 포함
SELECT employee_id
FROM hr.job_history
ORDER BY 1; -- 정렬하기
SELECT *
FROM (SELECT employee_id as id, job_id job, to_char(salary) sal
FROM hr.employees
UNION ALL
SELECT employee_id, job_id, '무급'
FROM hr.job_history
ORDER BY 3 DESC)
WHERE sal = '무급';
2. 교집합 INTERSECT
SELECT employee_id
FROM hr.employees
INTERSECT
SELECT employee_id
FROM hr.job_history;
SELECT employee_id, job_id
FROM hr.employees
INTERSECT
SELECT employee_id, job_id
FROM hr.job_history;
3. 차집합 MINUS
SELECT employee_id -- 첫번째 SELECT 기준
FROM hr.employees
MINUS
SELECT employee_id -- 여기와 겹치는 것을 제외한다.
FROM hr.job_history; -- 100건
SELECT employee_id -- 첫번째 SELECT 기준
FROM hr.job_history
MINUS
SELECT employee_id -- 여기와 겹치는 것을 제외한다.
FROM hr.employees; -- 0건
SELECT employee_id, job_id
FROM hr.employees
MINUS
SELECT employee_id, job_id
FROM hr.job_history; -- 105건
[문제] job_id를 한번이라도 바꾼 사원들의 정보를 출력해주세요.
SELECT *
FROM hr.employees
WHERE employees_id 비교연산자 (job_id = 한번이상 바꾼 사원 사원번호);
+
(SELECT employee_id
FROM hr.job_history)
↓
SELECT *
FROM hr.employees
WHERE employee_id IN (SELECT employee_id
FROM hr.job_history);
+ ㄴ 중복값 보유
SELECT employee_id
FROM hr.employees
INTERSECT
SELECT employee_id
FROM hr.job_history;
↓
SELECT *
FROM hr.employees
WHERE employee_id IN (SELECT employee_id
FROM hr.employees
INTERSECT
SELECT employee_id
FROM hr.job_history); -- 비효율적
↓
SELECT *
FROM hr.employees e
WHERE EXISTS (SELECT 'X'
FROM hr.job_history
WHERE employee_id = e.employee_id); -- 최적화
[문제] job_id를 한번도 바꾸지 않은 사원들의 정보를 출력해주세요.
SELECT *
FROM hr.employees
WHERE employee_id NOT IN (SELECT employee_id
FROM hr.job_history);
SELECT *
FROM hr.employees
WHERE employee_id NOT IN (SELECT employee_id
FROM hr.employees
INTERSECT
SELECT employee_id
FROM hr.job_history);
SELECT *
FROM hr.employees
WHERE employee_id IN (SELECT employee_id
FROM hr.employees
MINUS
SELECT employee_id
FROM hr.job_history);
SELECT *
FROM hr.employees e
WHERE NOT EXISTS (SELECT 'X'
FROM hr.job_history
WHERE employee_id = e.employee_id); --> 최적화
[문제] 부서가 소재하지 않은 국가 리스트가 필요하다. country_id, country_name 출력.
SELECT country_id, country_name
FROM hr.countries -- 전체목록에서
MINUS
SELECT c.country_id, c.country_name -- 부서지정한 목록을 정렬 후 제외
FROM hr.departments d, hr.locations l, hr.countries c
WHERE d.location_id = l.location_id
AND l.country_id = c.country_id; -- 큰데이터 2개를 정렬 후 비교 >> 속도저하
||
SELECT country_id, country_name
FROM hr.countries c
WHERE NOT EXISTS (SELECT 'X'
FROM hr.departments d, hr.locations l
WHERE d.location_id = l.location_id -- JOIN
AND l.country_id = c.country_id) -- country_id 체크
ORDER BY 1; -- 비교 후 정렬 >> 최적화
SELECT e.employee_id, d.department_name
FROM hr.employees e, hr.departments d
WHERE e.department_id(+) = d.department_id(+); -- 오류
↓
SELECT e.employee_id, d.department_name
FROM hr.employees e, hr.departments d
WHERE e.department_id = d.department_id(+)
UNION -- 비효율, 테이블 2번 엑세스
SELECT e.employee_id, d.department_name -- 정렬이 수행된다
FROM hr.employees e, hr.departments d
WHERE e.department_id(+) = d.department_id;
↓
[문제] UNION -> UNION ALL + NOT EXISTS 변환
SELECT e.employee_id, d.department_name
FROM hr.employees e, hr.departments d
WHERE e.department_id = d.department_id(+)
UNION ALL -- hr.employees 2번 엑세스
SELECT NULL, department_name
FROM hr.departments d
WHERE NOT EXISTS (SELECT 'X'
FROM hr.employees
WHERE department_id = d.department_id);
↓
SELECT e.employee_id, d.department_name
FROM hr.employees e FULL OUTER JOIN hr.departments d -- 최적화
ON e.department_id = d.department_id;
[문제]
1) department_id, job_id, manager_id 기준으로 총액 급여를 출력
SELECT department_id, job_id, manager_id, sum(salary)
FROM hr.employees
GROUP BY department_id, job_id, manager_id;
2) department_id, job_id 기준으로 총액급여를 출력
SELECT department_id, job_id, sum(salary)
FROM hr.employees
GROUP BY department_id, job_id;
3) department_id 기준으로 총액급여를 출력
SELECT department_id, sum(salary)
FROM hr.employees
GROUP BY department_id;
4) 전체 총액 급여를 출력
SELECT sum(salary)
FROM hr.employees;
1),2),3),4)를 한꺼번에 출력해주세요.
SELECT department_id, job_id, manager_id, sum(salary)
FROM hr.employees
GROUP BY department_id, job_id, manager_id
UNION ALL
SELECT department_id, job_id, NULL, sum(salary)
FROM hr.employees
GROUP BY department_id, job_id
UNION ALL
SELECT department_id, NULL, NULL, sum(salary)
FROM hr.employees
GROUP BY department_id
UNION ALL
SELECT NULL, NULL, NULL, sum(salary)
FROM hr.employees;
↓
■ ROLLUP 그룹화
- GROUP BY 절에 지정된 열 리스트를 오른쪽에서 왼쪽방향으로 이동하면서 그룹화를 만드는 연산자
예시)
SELECT a, b, c, sum(sal)
FROM test
GROUP BY a, b, c;
sum(sal) = {a,b,c}
↓
SELECT a, b, c, sum(sal)
FROM test
GROUP BY ROLLUP(a, b, c);
sum(sal) = {a,b,c}
= {a,b}
= {a}
= {}
SELECT department_id, job_id, manager_id, sum(salary)
FROM hr.employees
GROUP BY ROLLUP(department_id, job_id, manager_id);
sum(salary) = {department_id, job_id, manager_id}
= {department_id, job_id}
= {department_id}
= {}
■ CUBE
- ROLLUP 연산자 기능을 포함하고 모든 그룹화를 할 수 있도록 만드는 연산자.
- 모든 경우의 수
SELECT a, b, c, sum(sal)
FROM test
GROUP BY CUBE(a, b, c);
sum(sal) = {a,b,c}
= {a,b}
= {a,c}
= {b,c}
= {a}
= {b}
= {c}
= {}
SELECT department_id, job_id, manager_id, sum(salary)
FROM hr.employees
GROUP BY CUBE(department_id, job_id, manager_id);
sum(salary) = {department_id, job_id, manager_id}
= {department_id, job_id}
= {department_id, manager_id}
= {job_id, manager_id}
= {department_id}
= {job_id}
= {manager_id}
= {}
예)
sum(sal) = {a,b}
= {a,c}
↓
SELECT a, b, NULL, sum(sal)
FROM test
GROUP BY a, b
UNION ALL
SELECT a, NULL, c, sum(sal)
FROM test
GROUP BY a, c;
↓
■ GROUPING SETS
- 내가 원하는 그룹을 만드는 연산자
SELECT a, b, C, sum(sal)
FROM test
GROUP BY GROUPING SETS((a, b),(a,c),());
sum(sal) = {a,b}
= {a,c}
= {}
SELECT department_id, job_id, manager_id, sum(salary)
FROM hr.employees
GROUP BY GROUPING SETS((department_id, job_id),(department_id,manager_id),());
sum(salary) = {department_id, job_id}
= {department_id,manager_id}
= {}
[문제] 년도 분기별 총액을 구하세요. 행의 합과 열의 합도 구하세요. ★★★★★
1. 연도별 분기별 출력 + GROUP BY CUBE로 그룹별 합계 출력
SELECT to_char(hire_date,'yyyy') year, to_char(hire_date, 'q') quater, sum(salary) sumsal
FROM hr.employees
GROUP BY CUBE (to_char(hire_date,'yyyy'), to_char(hire_date, 'q'));
2. InlineView + nvl(quater,0) null값을 칼럼으로 활용가능하게 데이터로 변경
SELECT year, nvl(quater,0) quater, sumsal
FROM (SELECT to_char(hire_date,'yyyy') year, to_char(hire_date, 'q') quater, sum(salary) sumsal
FROM hr.employees
GROUP BY CUBE (to_char(hire_date,'yyyy'), to_char(hire_date, 'q')));
3. InlineView + 세로형 테이블로 변환
SELECT *
FROM (SELECT year, nvl(quater,0) quater, sumsal
FROM (SELECT to_char(hire_date,'yyyy') year, to_char(hire_date, 'q') quater, sum(salary) sumsal
FROM hr.employees
GROUP BY CUBE (to_char(hire_date,'yyyy'), to_char(hire_date, 'q'))))
PIVOT (max(sumsal) FOR quater IN (1 Q1, 2 Q2, 3 Q3, 4 Q4, 0 합))
ORDER BY 1;
4. InlineView + 데이터 내 NULL값 변환
SELECT nvl(year,'합') 년도, nvl(Q1,0) "1분기", nvl(Q2,0) "2분기", nvl(Q3,0) "3분기", nvl(Q4,0) "4분기", 합
FROM (SELECT *
FROM (SELECT year, nvl(quater,0) quater, sumsal
FROM (SELECT to_char(hire_date,'yyyy') year, to_char(hire_date, 'q') quater, sum(salary) sumsal
FROM hr.employees
GROUP BY CUBE (to_char(hire_date,'yyyy'), to_char(hire_date, 'q'))))
PIVOT (max(sumsal) FOR quater IN (1 Q1, 2 Q2, 3 Q3, 4 Q4, 0 합))
ORDER BY 1);
■ 계층검색(hierarchical query)
- 조직도, 게시판 연결글, 탐색기
- CONNECT BY PRIOR ~
SELECT *
FROM hr.employees
START WITH employee_id = 101 -- 시작점, 첫번째 무조건 출력
CONNECT BY PRIOR employee_id = manager_id; -- 연결고리 조건
ㄴ 전단계 사원번호를 상사번호로 연결하여 해당 행을 출력, 위에서 밑으로 검색
1. 101번 사원 출력
2. 101번을 manager_id로 갖고 있는 사원의 행 출력 -> 108번 사원 출력
3. 108번을 manager_id로 갖고 있는 사원의 행 출력 -> 없음 -> 전단계
4. 101번을 manager_id로 갖고 있는 사원의 행 출력 -> 109번 사원 출력
...
- 시작점부터 연결된 하위 자료 모두 출력
- CONNECT BY ~ PRIOR ~
SELECT *
FROM hr.employees
START WITH employee_id = 101 -- 시작점, 무조건 출력
CONNECT BY employee_id = PRIOR manager_id; -- 연결고리 조건
ㄴ 전단계 상사번호를 사원번호로 연결하여 해당 행을 출력, 밑에서 위로 검색
1. 101번 사원 출력
2. 101번 사원의 manager_id를 employee_id에서 찾기 -> 100번 사원 출력
3. 100번 사원의 manager_id를 employee_id에서 찾기 -> 없다 -> 종료
- 시작점부터 연결된 상위 자료만 출력
SELECT level, last_name
FROM hr.employees
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id;
↓
SELECT level, lpad(' ',level*2-2,' ')||last_name
FROM hr.employees
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id;
SELECT level, lpad(' ',level*2-2,' ')||last_name
FROM hr.employees
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id
ORDER SIBLINGS BY last_name; -- 칼럼명 사용
- 계층검색에서 정렬을 수행하려면 ORDER SIBLINGS BY 로 작성해야 한다.
- ORDER SIBLINGS BY 에서는 위치표기법, 열별칭을 사용할 수 없다.
SELECT level, lpad(' ',level*2-2,' ')||last_name
FROM hr.employees
WHERE employee_id != 101 -- 101번 행 제외 : WHERE 절에 작성
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id
ORDER SIBLINGS BY last_name;
SELECT level, lpad(' ',level*2-2,' ')||last_name
FROM hr.employees
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id
AND employee_id != 101 -- 101번 조직 제외 : CONNECT BY 다음 AND에서 작성
ORDER SIBLINGS BY last_name;
# SELECT문으로 번호만들기
- CONNECT BY
- 시작 기본값 1
[문제] SELECT문을 이용해서 1~100 출력해주세요.
SELECT level
FROM dual
CONNECT BY level <= 100;
[문제] SELECT문을 이용해서 2단을 출력해주세요.
SELECT '2 * ' || level || ' = ' || 2 * level "2단"
FROM dual
CONNECT BY level < 10;
[문제] SELECT문을 이용해서 2단~9단까지 출력해주세요.
SELECT dan ||' * '|| num ||' = '|| dan*num 구구단
FROM (SELECT level + 1 dan
FROM dual
CONNECT BY level <= 8), -- 메인반복문
(SELECT level num
FROM dual
CONNECT BY level <= 9); -- 서브반복문
'Oracle SQL' 카테고리의 다른 글
09-2 권한, 테이블, INSERT, UPDATE, DELETE (0) | 2023.10.18 |
---|---|
09 WITH (0) | 2023.10.18 |
07 PIVOT, UNPIVOT, SCALAR SUBQUERY (0) | 2023.10.16 |
06 SUBQUERY (0) | 2023.10.13 |
05 JOIN (0) | 2023.10.12 |