- DB에서 함수는 반드시 한 개의 리턴값이 있어야 한다.
단일행 함수
- input 하나의 행 → output 하나
- 데이터 종류별로 여러 개의 함수가 있다.
다중행 함수
- input 여러 개의 행 → output 하나
- 계산과 관련된 함수가 주를 이룬다.
- count, max, min, sum
- 계산함수, 그룹함수 라고도 한다.
단일행 함수
1. 수학 함수
반올림 관련 함수
round
자릿수 지정 반올림
trunc
자릿수 지정 버림
floor
최하 정수 리턴
ceil
최상 정수 리턴
예제
- 사원명, 급여, 월급(급여/12), 세금(급여의 3.3%)을 추출. 단 월급은 10단위에서 반올림하고, 세금은 원단위에서 절삭
select
saname "사원명",
sapay "급여",
round(sapay / 12, 3)*10000 "월급",
trunc(sapay*0.033, 4)*10000 "세금"
from sawon;
select
saname "사원명",
sapay "급여",
round(sapay / 12, 3) "월급",
trunc(sapay*0.033, 4) "세금"
from sawon;
2. 문자열 함수
길이
lenght
문자열 길이
lengthb
문자열 길이 (바이트 단위)
공백 제거
trim
양쪽 공백 제거
rtrim
오른쪽 공백 제거
ltrim
왼쪽 공백 제거
- 문자열 제거
select trim('k' from 'kibwa kibwa') from dual;
대소문자 전환
lower
모든 문자를 소문자로
upper
모든 문자를 대문자로
initcap
단어의 첫글자만 대문자로
문자열 대체
select replace('i am a kibwa', 'a', 'x') from dual;
채우기 함수
lpad
rpad
- *pad(’데이터’, 전체크기, ‘채울 문자열’)
select lpad(saname, 20, '#') a, rpad(saname, 20, '&') a from sawon;
예제
- 사원명, 급여, 급여현황(급여가 100단위에 ‘*’ 하나) 추출
col 급여현황 format a50
select
saname,
sapay,
lpad('*', (sapay / 100), '*') "급여현황"
from sawon;
SANAME SAPAY 급여현황
홍길동 5000 **************************************************
한국남 3000 ******************************
이순신 3500 ***********************************
이순라 1200 ************
놀기만 2300 ***********************
류별나 1600 ****************
채시라 3400 **********************************
이성계 2803 ****************************
무궁화 3000 ******************************
임꺽정 2200 **********************
깨똥이 4500 *********************************************
문자열 찾기
문자열 추출
- substr(문자열, 시작자릿수, 찾을문자개수) → 시작자릿수 문자부터 n개의 문자열 반환
예제
- 고객명, 전화번호, 주민번호1(**-1234567), 주민번호2(123456-***)
select lpad(substr(gojumin, 7, 14), 14, '*') "주민번호 1" from gogek;
select rpad(substr(gojumin, 1, 7), 14, '*') "주민번호 2" from gogek;
select goname "고객명", gotel "전화번호",
lpad(substr(gojumin, 7, 14), 14, '*') "주민번호 1",
rpad(substr(gojumin, 1, 7), 14, '*') "주민번호 2"
from gogek;
decode
decode(deptno, 10, '영업', 20, '관리', 30, '총무', '전산')
CASE
select saname, deptno,
case deptno when 10 then '영업'
when 20 then '관리'
when 30 then '총무'
else '전산' end "부서명"
from sawon;
예제
- 고객명, 전화번호, 성별 추출 (decode)
select
goname "고객명",
gotel "전화번호",
decode(substr(gojumin, 8, 1),
1, '남자', 2, '여자', '선택안함') "성별"
from gogek;
- 사원명, 급여, 보너스 출력(case)
- 단, 보너스는 급여가 1000미만이면 급여의 10%, 1000~2000이면 급여의 15%, 2000 초과하면 급여의 20%
select
saname,
sapay,
case when sapay < 1000 then floor(sapay * 0.1)
when sapay <= 2000 then floor(sapay * 0.15)
when sapay > 2000 then floor(sapay * 0.2)
else 0
end "보너스"
from sawon;
4. 변환 함수
- to_char(’날짜’ | ‘숫자’ , ‘형식’)
예제
select
to_char(sysdate, 'yy') "yy",
to_char(sysdate, 'year') "year",
to_char(sysdate, 'month') "month",
to_char(sysdate, 'mon') "mon",
to_char(sysdate, 'mm') "mm",
to_char(sysdate, 'q') "q",
to_char(sysdate, 'd') "d",
to_char(sysdate, 'day') "day",
to_char(sysdate, 'dy') "dy",
to_char(sysdate, 'dd') "dd",
to_char(sysdate, 'ddd') "ddd",
to_char(sysdate, 'hh') "hh",
to_char(sysdate, 'hh24') "hh24",
to_char(sysdate, 'miss') "miss",
to_char(sysdate, 'am') "am",
to_char(sysdate, 'pm') "pm"
from dual;
select
to_char(sysdate, 'fmyyyy.mm.dd day am hh:mi:ss')
from dual;
select
to_char(sysdate, 'fmyyyy.mmsp.dd day am hh:mi:ss')
from dual;
select
to_char(sysdate, 'fmyyyy.mm.ddth day am hh:mi:ss')
from dual;
- 오늘 날짜를 [2022년 7월 20일 수요일] 형태로 추출
select to_char(sysdate, 'fm yyyy"년" mm"월" dd"일" day') from dual;
숫자 관련 형식 종류
- 9는 해당 자리에 데이터가 있는 경우 출력하고, 없으면 출력하지 않는다.
- 0은 해당 자리의 데이터를 무조건 출력한다.
- FM은 9로 치환된 소수점 이상의 공백 및 소수점 이하의 9을 제거한다.
- FM이 없으면 숫자 소수점 이상은 공백으로, 소수점 이하는 0으로 표시된다.
SQL> select to_char(sapay, '$9,990') from sawon;
TO_CHAR
$5,000
$3,000
$2,000
$400
$1,003
SQL> select to_char(sapay, 'fm$9,990') from sawon;
TO_CHAR
$5,000
$3,000
$2,000
$400
$1,003
5. 날짜 함수
- last_day(A) - A 월의 마지막 날짜
- next_day(A, ‘월’) - 처음으로 돌아오는 요일의 날짜
- add_months(A, n) - A로부터 n개월 뒤의 날짜
SQL> select
last_day(sysdate),
next_day(sysdate, '월'),
add_months(sysdate, 3)
from dual;
LAST_DAY NEXT_DAY ADD_MONT
22/07/31 22/07/25 22/10/20
- months_between(A, B) - A, B의 개월 수 차이
- 소수점 아래는 의미 없는 쓰레기값
SQL> select months_between(sysdate, '97/02/26') from dual;
MONTHS_BETWEEN(SYSDATE,'97/02/26')
304.826807
예제
- 사원명, 입사일, 근무기간 (xx년 xx개월)
- col 근무기간 format a20
select
saname,
sahire,
floor(months_between(sysdate, sahire)/12)||'년 '
||floor(mod(months_between(sysdate, sahire), 12))||'개월'
"근무기간"
from sawon;
SQL> select
2 saname,
3 sahire,
4 floor(months_between(sysdate, sahire)/12)||'년 '
5 ||floor(mod(months_between(sysdate, sahire), 12))||'개월'
6 "근무기간"
7 from sawon;
SANAME SAHIRE 근무기간
홍길동 80/01/01 42년 6개월
한국남 88/11/01 33년 8개월
이순신 85/03/01 37년 4개월
이순라 90/05/01 32년 2개월
날짜 연산
select
saname,
sahire,
sahire + to_yminterval('01-06') "승급날짜"
from sawon;
SANAME SAHIRE 승급날짜
홍길동 80/01/01 81/07/01
한국남 88/11/01 90/05/01
이순신 85/03/01 86/09/01
이순라 90/05/01 91/11/01
select
saname,
sahire,
sahire + to_dsinterval('100 00:00:00') "계약종료"
from sawon;
SANAME SAHIRE 계약종료
홍길동 80/01/01 80/04/10
한국남 88/11/01 89/02/09
이순신 85/03/01 85/06/09
이순라 90/05/01 90/08/09
- round, trunc - 지정한 기준의 하위 단계에서 반올림/버림
select
saname,
sahire,
round(sahire, 'year')
from sawon;
SANAME SAHIRE ROUND(SA
홍길동 80/01/01 80/01/01
한국남 88/11/01 89/01/01
이순신 85/03/01 85/01/01
이순라 90/05/01 90/01/01
select
trunc(sysdate, 'month')
from dual;
TRUNC(SY
22/07/01
6. rank 함수 (통계함수)
rank() over(**[partition by 컬럼명]** order by 컬럼명 [(asc)|desc]) "석차"
select
saname,
sahire,
rank() over(order by sahire) "근무연차 랭킹"
from sawon;
SANAME SAHIRE 근무연차 랭킹
홍길동 80/01/01 1
김유신 81/04/01 2
이미라 83/04/01 3
이성계 84/05/01 4
무궁화 84/08/01 5
- 부서별 급여를 많이 받는 순서대로 랭킹 추출
- null을 포함하지 않도록 주의
select
deptno,
saname,
sapay,
rank() over(partition by deptno order by sapay desc) "부서별 급여 랭킹"
from sawon
where sapay is not null;
DEPTNO SANAME SAPAY 부서별 급여 랭킹
10 홍길동 5000 1
10 깨똥이 4500 2
10 무궁화 3000 3
10 최진실 2000 4
10 류명한 1800 5
10 무궁화 1100 6
20 이순신 3500 1
20 채시라 3400 2
20 한국남 3000 3
20 놀기만 2300 4
20 임꺽정 2200 5
20 류별나 1600 6
20 이순라 1200 7
30 공부만 4003 1
30 이성계 2803 2
30 이미라 2503 3
30 채송화 1703 4
30 공부해 1303 5
30 강감찬 1003 6
30 김유신 400 7
❓order by 를 제외하면 어떤 기준으로 정렬되어 출력될까? → rowid
- rowid = 행 주소
- 18자리 주소 중 마지막 3자리
- 분산 쿼리 - 100만개의 데이터가 있으면 10만개로 각각 나누어 저장해두고, 데이터를 찾을 때 10만개씩 10개의 묶음을 동시에 찾는다.
- 대량 데이터는 쪼개어 저장해야 한다 → partitioning table
SQL> select rowid, sabun, saname from sawon;
ROWID SABUN SANAME
AAASNVAAEAAAAImAAA 1 홍길동
AAASNVAAEAAAAImAAB 2 한국남
AAASNVAAEAAAAImAAC 3 이순신
AAASNVAAEAAAAImAAD 5 이순라
AAASNVAAEAAAAImAAE 7 놀기만
7. Group By
- 계산함수, 집계함수 사용
- sum, avg, count, max, min
- group by 절 : 그룹화 절
- having 절 : group by 에 대한 조건절
💡 **주의 : WHERE, HAVING, GROUP BY에는 별칭을 사용할 수 없다**
select
from
where
group by
having
order by
select
sajob,
count(*),
sum(sapay)
from sawon
group by sajob;
SAJOB COUNT(*) SUM(SAPAY)
과장 5 15903
사원 8 12606
대리 3 6006
회장 1 5000
부장 3 8803
- 성별, 직책별로 평균 급여와 인원수를 출력하되, 사원과 대리 직책만 추출, 인원수가 많은 순으로 정렬
select
sajob,
sasex,
count(*) "인원수",
avg(sapay) "평균급여"
from sawon
where sajob = '사원' or sajob = '대리'
group by sasex, sajob
order by 인원수 desc;
SAJOB SASE 인원수 평균급여
사원 남자 4 1226.5
사원 여자 4 1925
대리 여자 2 2103
대리 남자 1 1800
- 성별, 직책별로 평균 급여와 인원수를 출력하되, 사원을 제외하고 집계 인원수가 2명 이하인 것만 추출
select
sasex,
sajob,
avg(sapay) "평균급여",
count(*) "인원수"
from sawon
where sajob != '사원'
group by sasex, sajob
having count(*) <= 2;
SASE SAJOB 평균급여 인원수
남자 회장 5000 1
여자 부장 3000 1
남자 대리 1800 1
남자 부장 2901.5 2
여자 과장 1950 2
여자 대리 2103 2
select
to_char(sahire, 'yyyy') "입사년도",
avg(sapay) "평균급여 "
from sawon
group by to_char(sahire, 'yyyy');
입사 평균급여
1980 5000
1981 400
1983 2503
1984 1951.5
1985 3500
1986 1003
1988 2167.66667
1989 1600
1990 2500
1991 2000
1992 1703
rownum
- rownum : 추출되는 행의 순서를 의미
- 행을 제한할 때 (where 절) 사용
- 무조건 1부터 시작
select rownum, sabun, saname from sawon;
ROWNUM SABUN SANAME
1 1 홍길동
2 2 한국남
3 3 이순신
4 5 이순라
5 7 놀기만
6 11 류별나
7 14 채시라
8 17 이성계
select rownum, sabun, saname
from sawon
where rownum <= 3;
ROWNUM SABUN SANAME
1 1 홍길동
2 2 한국남
3 3 이순신
select rownum, sabun, saname
from sawon
where rownum > 3;
선택된 레코드가 없습니다.
select
ceil(rownum / 5) "group",
avg(sapay) "avg",
max(sapay) "max"
from sawon
group by ceil(rownum / 5);
group avg max
1 3000 5000
2 2600.6 3400
4 1441.8 2503
3 2621.2 4500
select
sajob,
sasex,
sum(sapay) "급여합계"
from sawon
group by sajob, sasex;
SAJOB SASE 급여합계
과장 남자 12003
부장 여자 3000
과장 여자 3900
대리 여자 4206
사원 여자 7700
대리 남자 1800
부장 남자 5803
사원 남자 4906
회장 남자 5000
rollup & cube
- group by와 함께 사용
- rollup : 1차 그룹에 대한 집계
select
sajob,
sasex,
sum(sapay) "급여합계"
from sawon
group by rollup(sajob, sasex);
SAJOB SASE 급여합계
과장 남자 12003
과장 여자 3900
과장 15903
대리 남자 1800
대리 여자 4206
대리 6006
부장 남자 5803
부장 여자 3000
부장 8803
사원 남자 4906
사원 여자 7700
SAJOB SASE 급여합계
사원 12606
회장 남자 5000
회장 5000
48318
- cube : rollup + 2차 그룹에 대한 집계
select
sajob,
sasex,
sum(sapay) "급여합계"
from sawon
group by cube(sajob, sasex);
SAJOB SASE 급여합계
48318
남자 29512
여자 18806
과장 15903
과장 남자 12003
과장 여자 3900
대리 6006
대리 남자 1800
대리 여자 4206
부장 8803
부장 남자 5803
SAJOB SASE 급여합계
부장 여자 3000
사원 12606
사원 남자 4906
사원 여자 7700
회장 5000
회장 남자 5000
- 단, NULL이 포함되어있는 경우 group by 에 의한 집계결과인지 일반집계결과인지 알 수 없다.
SAJOB SASE 급여합계
1000
49318
남자 1000
남자 30512
여자 18806
과장 15903
과장 남자 12003
과장 여자 3900
대리 6006
대리 남자 1800
대리 여자 4206
SAJOB SASE 급여합계
부장 8803
부장 남자 5803
부장 여자 3000
사원 12606
사원 남자 4906
사원 여자 7700
회장 5000
회장 남자 5000
grouping
을 사용해 이를 보완할 수 있다.
- group by 집계결과이면 1, 일반집계결과이면 0
select
sajob,
sasex,
sum(sapay) "급여합계",
grouping(sajob) JOB,
grouping(sasex) SEX
from sawon
group by cube(sajob, sasex);
SAJOB SASE 급여합계 JOB SEX
1000 0 1
49318 1 1
남자 1000 0 0
남자 30512 1 0
여자 18806 1 0
과장 15903 0 1
과장 남자 12003 0 0
과장 여자 3900 0 0
대리 6006 0 1
대리 남자 1800 0 0
대리 여자 4206 0 0
SAJOB SASE 급여합계 JOB SEX
부장 8803 0 1
부장 남자 5803 0 0
부장 여자 3000 0 0
사원 12606 0 1
사원 남자 4906 0 0
사원 여자 7700 0 0
회장 5000 0 1
회장 남자 5000 0 0
컬럼 그룹화
- 컬럼 제한이므로 select column from table 안에서 해결해야 한다.
- 조건명령(case, decode)와 계산함수를 사용한다. group by 사용 안함!
select
sum(decode(sajob, '사원', sapay, 0)) "사원",
sum(decode(sajob, '대리', sapay, 0)) "대리",
sum(decode(sajob, '과장', sapay, 0)) "과장",
sum(decode(sajob, '부장', sapay, 0)) "부장",
sum(decode(sajob, '이사', sapay, 0)) "이사"
from sawon;
사원 대리 과장 부장
12606 6006 15903 8803
select
sum(decode(sajob, '과장', 1, 0)) "과장",
sum(decode(sajob, '대리', 1, 0)) "대리",
sum(decode(sajob, '사원', 1, 0)) "사원",
sum(decode(sajob, '이사', 1, 0)) "이사"
from sawon;
과장 대리 사원 이사
5 3 8 0
select
count(decode(sajob, '과장', 1)) "과장",
count(decode(sajob, '대리', 1)) "대리",
count(decode(sajob, '사원', 1)) "사원",
count(decode(sajob, '이사', 1)) "이사"
from sawon;
과장 대리 사원 이사
5 3 8 0
select
sajob,
sum(decode(deptno, 10, sapay, 0)) "부서 10",
sum(decode(deptno, 20, sapay, 0)) "부서 20",
sum(decode(deptno, 30, sapay, 0)) "부서 30",
sum(decode(deptno, 40, sapay, 0)) "부서 40",
sum(sapay) "급여합계"
from sawon
where deptno is not null
group by sajob;
SAJOB 부서 10 부서 20 부서 30 부서 40 급여합계
과장 4500 7400 4003 0 15903
사원 3100 6800 2706 0 12606
대리 1800 0 4206 0 6006
회장 5000 0 0 0 5000
부장 3000 3000 2803 0 8803
select
sasex,
sajob,
deptno,
sum(sapay)
from sawon
group by grouping sets ((sasex, sajob), (sajob, deptno));
SASE SAJOB DEPTNO SUM(SAPAY)
남자 회장 5000
남자 사원 4906
여자 부장 3000
여자 사원 7700
남자 대리 1800
남자 1000
남자 부장 5803
남자 과장 12003
여자 과장 3900
여자 대리 4206
1000
SASE SAJOB DEPTNO SUM(SAPAY)
부장 20 3000
대리 30 4206
부장 10 3000
사원 10 3100
사원 20 6800
대리 10 1800
회장 10 5000
사원 30 2706
부장 30 2803
과장 10 4500
과장 30 4003
SASE SAJOB DEPTNO SUM(SAPAY)
과장 20 7400