Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

기록 저장소

3/4 [Database #8] 집합연산자, group by 본문

kitri 노트/oracle

3/4 [Database #8] 집합연산자, group by

resault 2019. 3. 10. 22:38

JOIN과 Subquery ]



3. 집합(Set) 연산자


1) Union : 두 질의 결과값의 합에서 중복을 제거 → 합집합

-- 부서번호가 50이거나 90인 사원과
-- 급여가 10000 이상인 사원의
-- 사번, 이름, 급여, 부서번호
select employee_id, first_name, salary, department_id
from employees
where department_id in (50, 90)
union        
select employee_id, first_name, salary, department_id
from employees
where salary >= 10000;


2) Union all : 두 질의 결과값의 합에서 중복을 포함  → 합집합 + 교집합

select employee_id, first_name, salary, department_id
from employees
where department_id in (50, 90)
union all
select employee_id, first_name, salary, department_id
from employees
where salary >= 10000;


3) Intersect : 교집합

select employee_id, first_name, salary, department_id
from employees
where department_id in (50, 90)
intersect
select employee_id, first_name, salary, department_id
from employees
where salary >= 10000;


4) Minus : 차집합

select employee_id, first_name, salary, department_id
from employees
where department_id in (50, 90)
minus
select employee_id, first_name, salary, department_id
from employees
where salary >= 10000;

-- 차이 확인!
select employee_id, first_name, salary, department_id
from employees
where salary >= 10000
minus
select employee_id, first_name, salary, department_id
from employees
where department_id in (50, 90);




[ Group by ]



1. 단일행을 이용한 Group by절


1) 기본 문법

-- 부서별 급여총합, 평균급여, 사원수, 최대급여, 최소급여
select department_id 부서번호, sum(salary) 급여총합, avg(salary) 평균급여,
        count(employee_id) 사원수, max(salary) 최대급여, min(salary) 최소급여
from employees
group by department_id;

- select 절에는 Groupping 한 컬럼과 Group 함수만 쓸 수 있음



2) group 함수 : avg, count, max, min, sum
    * 그룹 함수는 where 조건절에 사용할 수 없음. 


3) Having 절 : group by의 조건절
    * 일반 조건은 where 절에, group by의 조건은 having 절에!

-- 부서별 급여총합, 평균급여, 사원수, 최대급여, 최소급여
-- 평균급여가 5000 이하인 부서
select department_id 부서번호, sum(salary) 급여총합, avg(salary) 평균급여,
        count(employee_id) 사원수, max(salary) 최대급여, min(salary) 최소급여
from employees
group by department_id
having avg(salary) <= 5000;


4) 응용

--1. 모든 부서의 평균 급여(각 부서별 평균)보다 많이 받는 사원의
-- 사번, 이름, 급여
select employee_id, first_name, salary
from employees
where salary > all ((select avg(salary)
                       from employees
                       group by department_id
                      )
                     );

--2. 부서별 최고 급여를 받는 사원의
-- 부서이름, 사번, 이름, 급여 (단, 부서가 없는 사원은 제외한다)
select (select department_name from departments where e.department_id = department_id) 부서이름,
        e.employee_id 사번, e.first_name 이름, e.salary 급여
from employees e, (select department_id, max(salary) 급여
                    from employees
                    group by department_id
                    having department_id is not null) m
where e.salary = m."급여"
        and e.department_id = m.department_id;

--3-1 부서가 없는 사원을 포함하려면?
select (select department_name from departments where e.department_id = department_id) 부서이름,
        e.employee_id 사번, e.first_name 이름, e.salary 급여
from employees e, (select department_id, max(salary) 급여
                    from employees
                    group by department_id
                    having department_id is not null) m
where e.salary = m."급여"
        and e.department_id = m.department_id
union
select (select department_name from departments where e.department_id = department_id) 부서이름,
        e.employee_id 사번, e.first_name 이름, e.salary 급여
from employees e, (select department_id, max(salary) 급여
                    from employees
                    group by department_id
                    having department_id is null) m
where e.salary = m."급여";

--3-2. where 절에서 is null을 쓰면?
select (select department_name from departments where e.department_id = department_id) 부서이름,
        e.employee_id 사번, e.first_name 이름, e.salary 급여
from employees e, (select department_id, max(salary) 급여
                    from employees
                    group by department_id) m
where e.salary = m."급여"
        or e.department_id is null    -- 지금은 값이 같지만, null인 사람이 여러명인 경우라면 max 자체가 제대로 안나올 것임
        and e.department_id = m.department_id;



5) Top N Query

(1) 예제

-- 사번, 이름, 급여, 입사연대, 부서이름
-- 급여순 순위,
-- 한 페이지당 5명씩 출력된다고 가정할 때, 2쪽을 출력할 것
-- 1980년대, 1990년대, 2000년대
select b.rn 급여순위, b.employee_id 사번, b.first_name 이름, b.salary 급여,
        case
            when to_char(b.hire_date, 'yyyy') < '1990'    -- 범위비교를 하는 것이므로, 의미상 decode 보다는 case가 적합함
            then '1980년대'
            when to_char(b.hire_date, 'yyyy') < '2000'
            then '1990년대'
            else '2000년대'
        end 입사연대,
        d.department_name 부서이름
from (select rownum rn, a.*
       from (select employee_id, first_name, salary, hire_date, department_id
              from employees
              order by salary desc) a
       where rownum <= &page * 5) b, departments d
where b.department_id = d.department_id(+)
        and b.rn > &page * 5 - 5    -- 변수로 지정할 경우도 고려해야 하므로 숫자는 통일되게 계산하는 것이 좋음
order by 급여순위;    --? 이게 갑자기 왜 순서가 바뀌었을까??


-- 오답체크
select e.employee_id 사번, e.first_name 이름, e.salary 급여,
        decode( substr( to_char(e.hire_date, 'yyyy') , 3, 2),
                '1980', '1980년대',
                '1990', '1990년대',
                '2000년대') "입사 연대",
        (select department_name from departments where e.department_id = department_id) "부서이름"    --이 부분 확인!!!
from (select rownum 순번, employee_id
       from (select employee_id
              from employees
              order by salary desc)) s, employees e
where s.employee_id = e.employee_id
        and s.순번 between ((&page*5)-4) and (&page * 5);


(2) 관련 함수

▷ Rank | Dense_rank | Row_number () OVER ( [ PARTITION BY colum_name ] ORDER BY colum [ ASC | DESC ] )

- prtition by 뒤에 컬럼을 입력하여 그룹별로 순번을 부여할 수 있음
- 정렬 기본값은 asc
- 값이 중복되더라도 중복순위 없이 유일값을 부여함


&page : 변수 값 받아오기

select *
from employees
where salary > &page;


rownum : 행번호 

- order by로 지정하기 이전의 행번호를 가상의 컬럼에 보여주는 것. (roww_number 함수와 달리 아래와 같은 제약조건이 있음)
- 작다 비교는 가능 (rownum의 최소값이 1이므로)
- 크다 비교는 불가 (rownum의 최대값은 무한대이므로)

select rownum, employee_id, salary
from employees
where rownum < 10;

-- 크다비교 >> 에러
select rownum, employee_id, salary
from employees
where rownum > 5;




- end.








'kitri 노트 > oracle' 카테고리의 다른 글

3/6 [Database #10] DML, Transaction, Squence  (0) 2019.03.10
3/5 [Database #9] DDL, DML  (0) 2019.03.10
2/28 [Database #7] Subquery  (0) 2019.03.10
2/27[ Database#6] Join  (0) 2019.03.10
2/26 [Database#5] 일반/ 그룹함수, Join  (0) 2019.03.10