▣오늘의 주요 키워드▣
- case, decode에서 null check
- 날짜에서 RR vs YY
- 그룹함수
- group by, having
- sql 실행순서
- join
[문제30] JOB_ID 열의 값을 기반으로 모든 사원의 등급을 표시하는 query를 작성합니다.
<화면출력>
JOB_ID GRADE
--------- -------
AD_PRES A
ST_MAN B
IT_PROG C
SA_REP D
ST_CLERK E
Z
...
1) DECODE
SELECT job_id,
DECODE(job_id,'AD_PRES','A',
'ST_MAN','B',
'IT_PROG','c',
'SA_REP', 'D',
'ST_CLERK','E','Z') GRADE
FROM employees;
2)case
SELECT job_id,
case
when job_id = 'AD_PRES' then
'A'
when job_id = 'ST_MAN' then
'B'
when job_id = 'IT_PROG' then
'c'
when job_id = 'SA_REP' then
'D'
when job_id = 'ST_CLERK' then
'E'
else 'Z'
end GRADE
FROM employees;
2-2)case2
SELECT job_id,
case job_id
when 'AD_PRES' then
'A'
when 'ST_MAN' then
'B'
when 'IT_PROG' then
'c'
when 'SA_REP' then
'D'
when 'ST_CLERK' then
'E'
else 'Z'
end GRADE
FROM employees;
-decode 함수 괄호 안에서 마지막에 기준값 안 적으면 null이 출력
SELECT job_id,
case
when job_id in('AD_PRES', 'AC_MGR') then 'A' --다른 비교연산자가 사용되면 기준값을 when절에 다 표현해줘야 함
when job_id = 'ST_MAN' then 'B'
when job_id = 'IT_PROG' then 'c'
when job_id = 'SA_REP' then 'D'
when job_id = 'ST_CLERK' then 'E'
else 'Z'
end GRADE
FROM employees;
SELECT employee_id,
nvl2(commission_pct, (salary*12)+(salary*12*commission_pct), salary*12) ann_sal
FROM employees;
/* --nvl2함수
if commission_pct is not null then
(salary*12)+(salary*12*commission_pct)
else
salary*12
end if;
*/
decode, case 표현식에서 null check 방법
※decode 함수에서는 null keyword를 이용해서 null check해야 한다.
SELECT employee_id,
decode(commission_pct,
null, salary*12, --null키워드 사용, is null 사용x
(salary*12)+(salary*12*commission_pct)) ann_sal
FROM employees;
※case 표현식에서 is null 연산자를 이용해서 null check 해야 한다.
SELECT employee_id,
case
when commission_pct is null then --null키워드 사용 x, is null or is not null연산자 사용해야함
salary * 12
else
(salary*12)+(salary*12*commission_pct)
end ann_sal
FROM employees;
select
to_char(to_date('95-10-27','yy-mm-dd'), 'yyyy-mm-dd') YY,
to_char(to_date('95-10-27','rr-mm-dd'), 'yyyy-mm-dd') RR
FROM dual;
95-10-27
YY : 현재년도의 세기를 반영 : 2095-10-27
RR : 2000년도 표기법을 자동화로 변경해준다.
지정된(데이터입력)연도(년도)
0~49 50~99
현재연도(년도)
0~49 반환 날짜는 현재 세기를 반영 반환날짜는 이전세기를 반영
50~99 반환 날짜는 이후 세기를 반영 반환날짜는 현재세기를 반영
현재년도 데이터 입력날짜 YY RR
1994 92-10-27 1995 1995
1994 17-10-27 1917 2017
2001 17-10-27 2017 2017
2048 52-10-27 2052 1952
2051 47-10-27 2047 2147
★단일행 함수 -행당 하나의 결과를 반환하는 함수 -문자함수, 숫자함수, 날짜함수, 형변환함수, NULL관련함수, 조건제어 관련함서 |
★그룹함수 -여러행당(행짐합) 하나의 결과를 반환하는 함수 -sum, avg, median, variance, stddev, max, min, count -그룹함수에 입력하는 값이 숫자형만 입력해야하는 그룹함수 : sum, avg, median, variance, stddev -그룹함수에 입력하는 값이 모든 타입이 가능하는 그룹함수 : count, max, min -그룹함수는 null을 포함하지 않는다. 단 count(*)만 null을 포함 |
count : 행의 수를 구하는 함수
SELECT count(*)
FROM employees;
SELECT count(*) -- null포함한 행의 수를 구한다.
FROM employees
WHERE department_id = 50;
SELECT count(commission_pct), count(employee_id) --null제외한 행수를 구한다.
FROM employees
WHERE department_id = 50;
sum : 합
SELECT sum(salary)
FROM employees
WHERE department_id = 50; --department_id가 50인 것들만 salary를 다 더한 값
avg : 평균
SELECT avg(salary)
from employees;
SELECT avg(commission_pct) --null은 제외한 평균
FROM employees;
![]() |
![]() |
-소수점 자리수는 trunc함수로 제거하거나 round함수로 반올림하거나 하자
예)
1,null,2 --> (1+2)/2 --3명이지만 null은 빼고 2명만 계산함
만약에 전체 3으로 수행하려면?
--(1+2)/3 --> nvl함수로 null값을 0으로 대체하기
SELECT avg(nvl(commission_pct,0))
from employees;
--null값을 가지고 있는 인원도 포함시키기 위해서 null을 0으로 바꾸어서 계산한다
★median : 중앙값
-관측수(n) 홀수면 : (n+1)/2
-관측수(n) 짝수면 : 평균(n/2, (n+1)/2)
SELECT avg(salary), median(salary)
FROM employees;
자료의 중심 위치를 나타내는 대표값 | 자료의 퍼진 정도를 나타내는 값 |
평균(이상치데이터 때문에 문제스), 중앙값 | 분산, 표준편차, 범위, 사분위수 |
★variance : 분산, 편차 제곱의 합의 평균
SELECT variance(salary)
FROM employees;
★stddev : 표준편차
SELECT stddev(salary)
FROM employees;
★max : 최대값, min : 최솟값
SELECT max(salary), min(salary), max(salary)-min(salary)
FROM employees;
SELECT max(hire_date), min(hire_date), max(last_name), min(last_name)
FROM employees;
--가장 최근에 입사한 날짜, 가장 오래된 입사한 날짜, 끝 이름, 첫 이름
--즉 문자도 가능
★group by : 테이블의 행을 작은 그룹으로 나눌 수 있다.
SELECT department_id, sum(salary)
FROM employees
group by department_id;
※그룹 함수를 사용하실 때 주의할 점!!
- null 값은 포함하지 않음
- SELECT절에 그룹 함수에 포함되지 않는 개별 칼럼은 하나도 빠짐없이 group by절에 명시해야 함
- group by 절에는 열 별칭, 위치 표기법을 사용할 수 없음
SELECT department_id ,job_id, sum(salary) --sum(salary)는 그룹함수, 나머지가 개별컬럼
FROM employees
group by department_id, job_id;
오류 1. 별칭 사용
SELECT department_id dep_id,job_id, sum(salary)
FROM employees
group by dep_id, job_id; --group by절에서 컬럼의 별칭 사용 오류!
오류 2. 위치 표기법 사용
SELECT department_id dep_id,job_id, sum(salary)
FROM employees
group by 1, job_id; --group by절에서 컬럼의 위치표기법 사용하면 오류
오류 3. where절과 그룹 함수의 관계
SELECT department_id, sum(salary)
FROM employees
WHERE sum(salary) >= 10000
GROUP BY department_id;
--where절은 행을 제한하는 절이기 때문에 그룹함수의 결과를 제한하면 오류(그룹함수보다 먼저 돌아감)
★having : 그룹함수의 결과를 제한하는 함수(그룹 함수는 where이 아닌 having)
SELECT department_id, sum(salary)
FROM employees
GROUP BY department_id
having sum(salary) >= 10000 ;
SELECT department_id, job_id, sum(salary)
FROM employees
group by department_id, job_id
having count(*) > 5;
-여기서 난 헷갈린 부분이 있었다. having count(*)>5이면 department_id와 job_id를 그룹하고 거기서 5명 이상이 되는 department_id와 job_id를 뽑아내고 그들의 salary의 합을 구한다? 왜 3개 밖에 안 나올까? 뭔가 애매하고 무엇을 뜻하는지 잘 몰랐다.
-select 문에서 먼저 우선 생각해야 할 것이 sum(salary) 대신에 count(*)를 넣어서 출력해보면 밑에 사진처럼 출력이 된다. 이렇게 출력해보니까 왜 id가 3개가 나오는지 알게 되었다.
★SQL 실행 순서
-1.FROM -> 2.WHERE -> 3.GROUP -> 4.HAVING -> 5.SELECT -> 6.SORT
-먼저 테이블을 선택 - WHERE절 조건에 맞는 행 선택 - 그룹핑 -그룹핑된 행 그룹 함수조건으로 제한 -그룹함수 적용하고 난 뒤 출력할 컬럼 선택 - 정렬 -출력
SELECT department_id, sum(salary)
FROM employees
WHERE last_name like '%i%'
group by department_id
having sum(salary) >= 20000
order by 1;
오류! 그룹함수
-그룹 함수를 두 번 중첩할 때 개별 칼럼이 있으면 오류 발생
SELECT department_id, max(avg(salary))
FROM employees
GROUP BY department_id;
※여기서 궁금증
-그렇다면 department_id(개별 칼럼)을 없애면 department_id는 어떻게 열에 출력하지?
-정답은 sub query에 있다? (내일이나 모레 배운다고 넘어간다! 구글링으로 혼자 찾아보자)
[문제31] 2008년도에 입사한 사원들의 job_id별 인원수를 구하고 인원수가 많은 순으로 출력하세요.
SELECT department_id,job_id, count(job_id)
FROM employees
WHERE hire_date between to_date('2008/01/01', 'yyyy/mm/dd') and to_date('2008/12/31 23:59:59', 'yyyy/mm/dd hh24:mi:ss')
GROUP BY department_id,job_id
ORDER BY 3 desc;
------------강사님 답---------------
SELECT job_id, count(*) cnt
FROM employees
WHERE hire_date>=to_date('2008-01-01','yyyy-mm-dd')
and hire_date < to_date('2009-01-01', 'yyyy-mm-dd')
group by job_id
order by cnt desc;
[문제32] 년도별 입사한 인원수를 출력해주세요.
SELECT to_char(hire_date,'yyyy'), count(*)
FROM employees
group by to_char(hire_date,'yyyy')
order by 1;
[문제33] 월별 입사한 인원수 출력해주세요.
SELECT to_number(to_char(hire_date, 'mm')) month, count(employee_id)
FROM employees
group by to_number(to_char(hire_date, 'mm'))
order by 1;
[문제34] 아래 화면과 같이 출력해주세요.
TOTAL 2001년 2002년 2003년
---------- ---------- ---------- ----------
107 1 7 6
1)
SELECT count(*) total,
count(decode(to_char(hire_date,'yyyy'), '2001', 1)) "2001년", --이렇게 가로열로 2050년까지 뽑는다고 하면 비효율적이므로 서브쿼리를 사용해야함(다음주 수업까지 기다려야 한다고 함)
count(decode(to_char(hire_date,'yyyy'), '2002', 1)) "2002년",
count(decode(to_char(hire_date,'yyyy'), '2003', 1)) "2003년"
FROM employees;
2)
SELECT count(*) total,
count(case to_char(hire_date, 'yyyy') when '2001' then 'x' end) "2001년", --count는 문자든 숫자든 가능
count(case to_char(hire_date,'yyyy') when '2002' then 'x' end) "2002년",
count(case to_char(hire_date,'yyyy') when '2003' then 'x' end) "2003년"
FROM employees;
3)
SELECT count(*) total,
sum(case to_char(hire_date, 'yyyy') when '2001' then 1 end) "2001년", --sum은 문자가 안되고 숫자로
sum(case to_char(hire_date,'yyyy') when '2002' then 1 end) "2002년",
sum(case to_char(hire_date,'yyyy') when '2003' then 1 end) "2003년"
FROM employees;
-문제 34번은 내가 못 풀었다. 조건은 어떻게 넣지? 만 생각하다가 case, decode 배웠던 것을 까먹었었다..
문제를 해결하기 위해 어떻게 풀어나갈지 생각해보기 훈련!!
※강사님의 해결책 제시
count(if 입사한 년도 = '2001' then
end if)
이런 식으로 먼저 틀을 생각해보자
★JOIN (파이썬이나 R에서도 똑같이 사용됨)
-두 개 이상의 테이블에서 내가 원하는 데이터를 가져오는 방법
1.catesian product
- 조인 조건 생략된 경우
- 조인 조건 잘못 만든 경우
- 첫 번째 테이블 행의 수와 두 번째 테이블 행의 수가 곱해지는 현상
SELECT employee_id, department_name --employee_id 107명, department_name 27개
FROM employees, departments;
-위 코드는 107명의 employee_id와 부서 이름 출력하려고 하는 것인데 107 * 27로 한 명의 employee_id마다 27개의 department_name이 모두 출력되었다.
2.equi join, inner join, simple join, 등가 조인
SELECT employee_id, department_name
FROM employees, departments
WHERE department_id = department_id;
--ORA-00918: column ambiguously defined 오류
-위 코드는 employees테이블의 department_id와 department_id를 구분해야 하는 문제에 대한 조인
3. 해결책
SELECT e.employee_id, d.department_name
FROM employees e, departments d --테이블의 별칭을 사용하는 습관을 갖자
WHERE e.department_id = d.department_id; --조인조건 술어
[문제35]사원들의 사원번호, 근무 도시를 출력해주세요
SELECT e.employee_id, l.city
FROM employees e, locations l, departments d
WHERE e.department_id = d.department_id
and d.location_id = l.location_id;
-이 코드에서는 employees테이블의 employee_id와 location테이블의 city 칼럼을 중간다리 역할을 하는 departments 테이블까지 작성한 코드로 자세한 부분은 테이블들에 연결되어있는 밑에 있는 모델링 그림을 통해서 알아보자.
※n개의 테이블을 조인하려면 조인 조건 술어는 몇 개를 만들어야 하나요?
n-1개의 조인 조건 술어를 작성해야 한다.
[문제 36]사원들의 사원번호, 국가 이름을 출력해주세요
SELECT e.employee_id, c.country_id
FROM employees e, departments d, locations l, countries c
WHERE e.department_id = d.department_id --조인조건술어
and d.location_id = l.location_id --조인조건술어
and l.country_id = c.country_id; --조인조건술어
★employees 테이블 ![]() |
★departments 테이블 ![]() |
★locations 테이블 ![]() |
★countries 테이블 ![]() |
sql 테이블들의 model을 들어가 보면 이렇게 표현되어 있는데 후에 더 공부하고 해석할 예정이다.
대학교 다니던 시절에 소프트웨어공학에서 클래스 다이어그램이라고 배웠던 기억을 다시 떠올리며 오늘은 여기서 마무리하고 내일은 더 발전하고 성장하는 내가 되겠다.
'SQL' 카테고리의 다른 글
12.27 오늘의 공부 (0) | 2021.12.27 |
---|---|
12.24 오늘의 공부 (0) | 2021.12.24 |
12.23 오늘의 공부 (0) | 2021.12.23 |
12.21 오늘의 공부 (0) | 2021.12.21 |
12.20 오늘의 공부 (0) | 2021.12.20 |