SQL이론(4)

문제 : 우리회사에 근무하는 사원의 이름과 사원번호, 그리고 그 사원을 관리하는 관리자 번호와 이름을 출력하시오

현재 employee_id, last_name, manager_id는 employees테이블에 위치한다, 그러나 magager의 이름은 어디에도 위치하지 않는다. 아예 없는 컬럼이라 할 수 있다, 그렇기에 여기서는 self조인을 사용한다

self조인

SELECT e.employee_id, e.last_name, e.manager_id, m.last_name
from employees e, employees m
where e.manager_id = m.employee_id;

해석하면 from절을 보면 셀프조인을 통해 employees를 e와 m으로 따로 alias를 주어 새로운 테이블처럼 사용한다조인은 column이름이 같을때 (pk=fk)로 사용했지만 셀프조인에서는 데이터의 내용만 같다면 대입하여 사용이 가능하다. 여기서 employees 테이블의 manager_id는 결국 employee_id에 포함되어있기에 사용가능하다, 그래서 e.manager_id = m.employee_id로 사용

자체참조의 첫번째 데이터는 무조건 null값을 지닌다
대신 현업에서는 자주 사용안한다

해설 그림 그려서 넣기


함수 : 한개 또는 다수의 값을 받아들여서 함수가 가지고 있는 계산식을 통해 한개의 결과를 출력하는 것

단일, 다중, 그룹, WINDOWS로 이루어진다

그룹함수 : 그룹별로 제한하여 그룹 당 하나의 결과를 생성하는 함수

AVG : 평균
COUNT : 출력이 된 행의 개수
MAX : 최대
MIN : 최소
SUM : 총합
STDDEV
VARIANCE

기본적으로 그룹함수는 컬럼이름을 인수로 사용한다


AVG, MAX, MIN, SUM

SELECT avg(salary), sum(salary)
from employees;

여기서 hire_date, last_name으로 하면 오류뜸, sum과 avg는 산술연산을 통해 값을 구해주기 때문에 숫자데이터만 가능

SELECT min(hire_date), max(hire_date)
from employees;

해석하면 날짜는 제일 처음에 입사한 사람의 날짜, 제일 늦게 입사한 사람의 날짜
last_name, salary 둘다 결과값은 나오지만 사실 큰 의미는 없다
사원의 최소이름은? a부터 나오는데 이거는 사용에 의미가 없기에 숫자데이터와 쓰인다고 기억해두기


count(*) 는 출력이 되는 행의 개수를 결과로 출력한다

SELECT count(*)
from employees;
는 결과값이 107명으로 나온다 = 사원이 107명

count(column) 형태로도 가능하다

SELECT count(commission_pct)
from employees;
는 결과값이 35로 나온다 = 사원중 보너스 받는 사원 35명
SELECT count(commission_pct)
from employees
where department_id = 80
는 결과값이 34로 나온다 = 사원중 80번 부서에서 보너스 받는 사원 34명

이와 같이 count는 열과, 행 단위로 둘다 사용 가능하다

만약 사원들이 근무하고 있는 부서 개수가 몇개인지 알고싶다 할때

SELECT count(department_id)
from employees;
는 결과가 106으로 나온다

해석하면 사원테이블에서 사원번호 행의 개수가 몇개니? 라는 뜻으로 사원번호가 10에 10명 20에 45명 이런식으로 나오는게 아니라 한개의 행으로 읽어버려 사원 수 만큼 나오는 것이다. 또 여기서 전체 사원 수는 원래 107이기에 1명은 부서가 없다는 뜻으로 해석된다

그렇기에 문제를 풀고 싶다면 부서번호가 겹치는 항목은 제거해주어야하기 때문에
distinct로 중복제거

SELECT count(distinct department_id)
from employees;

주의!

만약 여기서 select 뒤에만 distinct와야한다면서요? 하면서 조건을 주게 된다면

SELECT distinct count(department_id)
from employees;

결과는 106이 나온다. department_id에 대해 중복을 제거한것이 아니라. count(department_id)의 결과는 106이고 여기에 중복을 제거한것이 때문에, 숫자인 106은 중복제거 해도 할 것이 없다.

그리고 생략되었지만 원래 식은 select avg(all salary)이런 형식으로 이루어진다, 디폴트 값이기 때문에 굳이 쓰지 않는 것!

SELECT count(distinct department_id)
from employees;
의 결과는 11이 나온다 = 11개의 부서가 존재한다는 소리


문제 : 사원들의 보너스 평균을 구하라, 평균과 sum을 사용한 값을 구하라

SELECT avg(commission_pct), sum(commission_pct)/107
from employees;
이렇게 된다면 둘의 결과값이 다르게 나옴

보너스의 평균과 합을 구해서 /사원수는 같지 않나? 하지만
그룹함수는 null값을 무시하기 때문에, null은 연산이 되지 않는다
그렇기에 정답은

SELECT avg(nvl(commission_pct,0)), sum(commission_pct)/107
from employees;

중첩함수 nvl를 사용해서 commission_pct의 값에 null이 있다면 0으로 처리하고 이의 평균을 구하면 된다


문제 : 부서별로 근무하는 사원 월급의 총합을 구하라

SELECT department_id, sum(salary)
from employees;

이러면 오류! sum은 그룹별로 묶어져서 계산이 되는데 department가 그룹화가 안되있다면 컴퓨터가 무엇을 계산해야하는지 모름..

그림이 엉망이지만, 예를 들어 현재 a라는 직업의 10번 부서에 100, 200 급여의 사원이 있고 20번부서에 100 급여를 가진 사원이 2명이 있다면 먼저 department를 10과 20으로 그룹화하고, 그 후 sum(salary)가 이루어져야하는데 위의 식은 그렇게 이루어지지 않았기에 오류가 뜸!!

그렇기에 group by 사용
group by는 그룹당 하나의 결과를 보여줄때 사용하는 함수

select
from
group by
order by
순서는 from - group by - select - ordr by 순서이다

group by 뒤에는 그룹함수가 사용되지 않은 모든 컬럼들이 명시되어야한다, 그룹화시켜줘야하기에

SELECT department_id, sum(salary)
from employees
group by department_id

경고! 그룹화를 그냥 사용하지 말기

select employee_id, sum(salary)
from employees
groupy employee_id 를 한다면?
결과는 107개가 나온다.

그룹화는 똑같은 것들을 하나의 그룹을 만들어서 계산을 도와주는 것인데, employee_id와 같은 pk는 중복된 값이 없이 각자의 값으로 존재하는 것이기 때문에 이것을 실행시키면 107개의 그룹화가 되어 그것의 합계가 나오게된다

이것은 그냥 select employee_id, salary
from employees와 같기 때문에 그룹화 할 상황아니면 쓰지 말기! 특히 pk는 사용하지 않기


그렇다면 grup by, order by를 같이 사용한다면?

select department_id dept_id, job_id, sum(salary)
from employees
group by department_id, job_id
order by department_id;

해석하면 사원테이블에서 사원번호와 직업을 그룹화하고 dept_id로 alias를 준 사원번호, 직업, 급여의 합을 사원번호를 기준으로 출력하라

여기서 dp_id를 기준으로 그룹화가 된후, job_id로 또 그룹화, 그 후 sum값이 나오게 된다


group by에 조건식을 주는 경우

select department_id, avg(salary)
from employees
where avg(salary) > 8000
group by department_id;

이 경우 오류!!
왜냐하면 where절은 그룹화되기 전에 필터링을 해주는 것이고 필터링 된 후 group by로 처리되는 것이다

그래서 조건을 주려면 where절과는 전혀 상관이 없고

group by에 대한 조건은 having으로 조건식을 줘야한다

select department_id, avg(salary)
from employees
having avg(salary) > 8000
group by department_id;

이렇게 해야 원하는 결과가 나옴


순서는 이렇게 외우기!!

select 5
from 1
where 2
group by 3
having 4 //group by와 세트메뉴, group조건줄때 사용
order by 6 //제일 마지막으로 기억하기!


문제 : 각 직업별 최대 급여, 최소급여, 급여의 총합, 평균 급여를 출력하고 직업을 오름차순으로 정렬하라. 단 이름을 MAX MIN SUM AVG로 출력하라

SELECT job_id, max(salary) as MAX , min(salary) as MIN, sum(salary) as SUM, avg(salary) af AVG
from employees
group by job_id
order by job_id;

결과가 어떻게 출력되어야 원하는 형태일지 잘 생각하고 select list에 적기!!
여기서 as로 alias주는게 제일 효율적이니 이렇게 사용하기


문제 : 동일한 직업을 가진 사원들의 총 수를 출력하시오

select job_id, sum(employee_id)
from employees
group by job_id;

문제: 매니저로 근무하는 사원들의 총 수를 출력하시오 (오답노트참조)

select count(distinct manager_id)
from employees;

좋은 웹페이지 즐겨찾기