| [문제] 최고 급여를 받는 사원의 정보, 부서 이름 정보를 출력해주세요. | 
| 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 |