[ORACLE] SQL 함수 활용 2
SQL 함수 활용 2
기본 SQL 이해 - 기본 함수 사용
변환 함수 : 날짜에 TO_CHAR 함수 사용
요소 | 결과 | 예시 |
---|---|---|
YYYY | 전체 년도를 숫자로 표기 | 2009 |
YEAR | 영문의 년도 표기 | TWO THOUSAND NINE |
MM | 월의 두 자릿수 표기 | 11 |
MONTH | 월의 전체 표기 | NOVEMER |
MON | 월의 세 글자 약식 표기 | NOV |
DY | 요일의 세 글자 약식 표기 | FRI |
DAY | 요일의 전체 표기 | FRIDAY |
D | 해당 주의 날짜 표기 | 6 |
DD | 해당 월의 날짜 표기 | 25 |
DDD | 해당 년의 날짜 표기 | 329 |
SELECT employee_id, TO_CHAR(hire_date, 'MM/YY') Month_Hired
FROM employees
WHERE last_name = 'Higgins'
EMPLOYEE_ID | MONTH_HIRED | |
---|---|---|
1 | 205 | 06/94 |
시간 요소는 날짜에서 시간 부분의 형식 지정 가능
| HH24:MI:SS AM | 15:45:32 PM | | — | — |
SELECT TO_CHAR(sysdate, 'YYYY-MM-DD:HH:MI:SS AM') FROM dual;
TO_CHAR(SYSDATE, ‘YYYY-MM-DD:HH:MI:SSAM’) 1 2021-07-10:02:03:57 PM -- HH뒤에 24를 추가하면 24시간제로 출력된다. -- 24시간제에서는 AM/PM을 쓰지 않는게 자연스러우므로 제외. SELECT TO_CHAR(sysdate, 'YYYY-MM-DD:HH24:MI:SS') FROM dual;
TO_CHAR(SYSDATE, ‘YYYY-MM-DD:HH24:MI:SS’) 1 2021-07-10:14:03:57 문자열은 큰 따옴표로 묶어서 추가 가능
| DD “of” MONTH | 12 of OCTOBER | | — | — |
숫자 접미어는 숫자를 영어 철자로 표기
| ddspth | fourteenth | | — | — |
ddspth
는 “날짜-스펠링-서수”를 뜻한다.-- 예제 -- 모든 사원의 성과 채용 날짜를 표시하되 -- 날짜를 "Seventeenth of June 1987 12:00:00 AM" 형식으로 출력 SELECT last_name, TO_CHAR(hire_date, 'fmDdspth "of" Month YYYY fmHH:MI:SS AM') HIREDATE FROM employees;
LAST_NAME HIREDATE 1 Whalen Seventeenth of September 1987 12:00:00 AM 2 Hartstein Seventeenth of February 1996 12:00:00 AM fmDdspth
에서의 “fm”은 0이나 공백을 제거해주는 역할을 한다.
변환 함수 : 숫자에 TO_CHAR 함수 사용
요소 | 결과 |
---|---|
9 | 자릿수 표기 |
0 | 강제 0 표기 |
$ | 달러 통화기호 표기 |
L | 해당 나라의 통화기호 표기 |
. | 소수점 표기 |
, | 천 단위 구분 기호 표기 |
SELECT TO_CHAR(salary, '$99,999.00') SALARY
FROM employees
WHERE last_name = 'Ernst';
SALARY | |
---|---|
1 | $6,000.00 |
정수의 자릿수가 지정된 범위를 초과하는 경우 숫자 대신 “#”으로 값이 출력된다.
함수 중첩
함수는 안쪽부터 실행된다.
F3(F2(F1(col, arg1), arg2), arg3)
-- F1, F2, F3 순으로 실행
SELECT last_name,
UPPER(CONCAT(SUBSTR (LAST_NAME, 1, 8), '_US'))
FROM employees
WHERE department_id = 60;
LAST_NAME | UPPER(CONCAT(SUBSTR(LAST_NAME, 1, 8),’_US’)) | |
---|---|---|
1 | Hunold | HUNOLD_US |
2 | Ernst | ERNST_US |
3 | Lorentz | LORENTZ_US |
Null 관련 함수
함수 | 설명 |
---|---|
NVL | null 값을 실제 값으로 변환합니다. |
NVL2 | expr1이 null이 아닌 경우 NVL2는 expr2를 반환합니다. expr1이 null인 경우 NVL2는 expr3을 반환합니다. 인수 expr1은 임의의 데이터 유형을 가질 수 있습니다. |
NULLIF | 두 표현식을 비교하여 같으면 null을 반환하고 같지 않으면 첫번째 표현식을 반환합니다. |
COALESCE | 표현식 리스트에서 null이 아닌 첫번째 표현식을 반환합니다. |
본래 NULL 값은 “알 수 없는 값”이므로 연산, 비교가 불가능하다.
하지만 위 함수들을 사용하여 연산, 비교를 가능하게 할 수 있다.
- NVL
표현식의 Data Type이 반드시 일치해야 함두 표현식의 데이터 타입이 일치하지 않을 경우, 다음의 규칙을 따른다.expr1
이 문자 데이터일 경우, 값을 비교하기 전에expr2
의 데이터 타입을expr1
의 데이터 타입과 일치시킨다. 또한expr1
의 문자 집합에서VARCHAR2
를 반환한다.expr1
이 숫자 데이터일 경우, 두 표현식 중 더 높은 우선순위를 가지는 데이터 타입으로 나머지를 묵시적 형변환시키고, 그 데이터 타입으로 값을 반환한다.- 형변환이 불가능할 경우, 에러를 출력한다.
- NVL(commission_pct, 0)
- NVL(hire_date, ‘01-JAN-97’)
- NVL(job_id, ‘No Job Yet’)
SELECT last_name, salary, NVL(commission_pct, 0), (salary*12) + (salary*12*NVL(commision_pct, 0)) AN_SAL FROM employees;
LAST_NAME SALARY NVL(COMMISSION_PCT,0) AN_SAL 1 Whalen 4400 0 52800 2 Hartstein 13000 0 156000 3 Fay 6000 0 72000 4 Higgins 12000 0 144000 5 Zlotkey 10500 0.2 151200 NVL(expr1, expr2)
는 “expr1”을 “expr2”로 변환하라는 의미이다.
- NVL2
- 첫 번째 표현식이 null이 아니면 두 번째 표현식을 반환, 첫 번째 표현식이 null이면 세 번째 표현식을 반환함 - NVL(expr1, expr2, expr3)
SELECT last_name, salary, commission_pct, NVL2(commission_pct, 'SAL+COMM', 'SAL') income FROM employees WHERE department_id IN (50, 80);
LAST_NAME SALARY COMMISSION_PCT INCOME 1 Mourgos 5800 (null) SAL 2 Rajs 3500 (null) SAL 3 Zlotkey 10500 0.2 SAL+COMM 4 Abel 11000 0.3 SAL+COMM - NULLIF
- NULLIF는 expr1과 expr2를 비교, 두 표현식이 같으면 null을 반환, 다르면 expr1을 반환 - NULLIF(expr1, expr2)
SELECT first_name, LENGTH(first_name) "expr1", last_name, LENGTH(last_name) "expr2", NULLIF(LENGTH(first_name), LENGTH(last_name)) result FROM employees;
FIRST_NAME expr1 LAST_NAME expr2 RESULT 1 Ellen 5 Abel 4 5 2 Curtis 6 Davies 6 (null) 3 Lex 3 De Haan 7 3 4 Bruce 5 Ernst 5 (null) - COALESCE
- COALESCE 함수는 여러 대체 값을 수용할 수 있음 - COALESCE(expr1, expr2, … exprn)
- 첫 번째 표현식이 null이 아닌 경우 COALESCE 는 해당 표현식을 반환, 그렇지 않은 경우 나머지 표현식에 계속 COALESCE 수행
SELECT last_name, employee_id, COALESCE(TO_CHAR(commission_pct), TO_CHAR(manager_id), 'No commission and no manager') FROM employees;
LAST_NAME EMPLOYEE_ID COALESCE(TO_CHAR(COMMISSI… 1 Whalen 200 101 2 Hartstein 201 100 3 King 100 No commission and no manager 4 Zlotkey 149 .2 5 Abel 174 .3
조건부 표현식 관련 함수(DECODE)
SQL 문에서 IF-THEN-ELSE 논리를 사용할 수 있다.
SELECT last_name, job_id, salary,
DECODE(job_id, 'IT_PROG', 1.10*salary,
'ST_CLERK', 1.15*salary,
'SA_REP', 1.20*salary,
salary)
REVISED_SALARY
FROM employees;
LAST_NAME | JOB_ID | SALARY | REVISED_SALARY | |
---|---|---|---|---|
1 | Ernst | IT_PROG | 6000 | 6600 |
2 | Lorentz | IT_PROG | 4200 | 4620 |
3 | Mourgos | ST_MAN | 5800 | 5800 |
4 | Rajs | ST_CLERK | 3500 | 4025 |
5 | Taylor | SA_REP | 8600 | 10320 |
job_id가 ‘IT_PROG’일 경우 salary에 1.10을 곱하는 식이다.
job_id가 ‘IT_PROG’, ‘ST_CLERK’, ‘SA_REP’ 모두 아닐 경우 그냥 salary를 출력한다.
모든 행에 대해서 값을 비교하게 된다.
조건부 표현식 관련 함수(CASE)
DECODE
와 마찬가지로 SQL 문에서 iF-THEN-ELSE 논리를 사용할 수 있다.
SELECT last_name, job_id, salary,
CASE job_id WHEN 'IT_PROG' THEN 1.10*salary
WHEN 'ST_CLERK' THEN 1.15*salary
WHEN 'SA_REP' THEN 1.20*salary
ELSE salary END "REVISED_SALARY"
FROM employees;
LAST_NAME | JOB_ID | SALARY | REVISED_SALARY | |
---|---|---|---|---|
1 | Whalen | AD_ASST | 4400 | 4400 |
2 | Hunold | IT_PROG | 9000 | 9900 |
3 | Mourgos | ST_MAN | 5800 | 5800 |
4 | Rajs | ST_CLERK | 3500 | 4025 |
5 | Taylor | SA_REP | 8600 | 10320 |
job_id가 ‘IT_PROG’일 경우 salary에 1.10을 곱한다.
job_id가 ‘IT_PROG’, ‘ST_CLERK’, ‘SA_REP’ 모두 아닐 경우 그냥 salary를 출력한다.
DECODE
와 비슷하지만 WHEN
, THEN
정도가 추가되었다.
또 조건비교에 있어서 크다(>
), 작다(<
), 같다(=
) 로직이 가능하다.
SELECT last_name, salary,
(CASE WHEN salary < 5000 THEN 'Low'
WHEN salary < 10000 THEN 'Medium'
WHEN salary < 20000 THEN 'Good'
ELSE 'Excellent'
END) as qualified_salary
FROM employees;
DECODE
는 단순한 equal(=
) 비교이다.
단순 비교가 필요할 때는 DECODE
를, 크기 비교와 같은 로직을 사용해야 할 때는 CASE
를 사용하도록 하자.
CASE 함수 응용 - Virtual Column
가상 칼럼이란?
테이블에 포함되는 일반적인 컬럼은 해당 데이터 타입에 맞는 데이터만 갖지만, 가상 칼럼은 여러 개의 데이터를 연산한 결과값을 저장하는 칼럼이다(11g NF).
CREATE TABLE copy_emp as SELECT * FROM emp; -- emp 테이블의 복사본 copy_emp 테이블 생성
ALTER TABLE copy_emp -- copy_emp 테이블에 sal_grade라는 virtual column 생성
ADD (sal_grade varchar(6)
AS (CASE
WHEN sal between 1 and 1000 THEN 'LOW'
WHEN sal between 1001 and 2000 THEN 'MEDIUM'
WHEN sal between 2001 and 3000 THEN 'HIGH'
ELSE 'ULTRA'
END) virtual);
SELECT ename, sal, sal_grade
FROM copy_emp;
INSERT INTO copy_emp(empno, ename, sal) values (9999,'LEE',4000);
-- 새 데이터 추가시 sal_grade에 해당하는 데이터는 넣지 않았지만, 자동으로 값이 할당됨
SELECT table_name, column_name, data_type, data_default
FROM user_tab_columns
WHERE table_name='COPY_EMP';
-- virtual column에 대한 정보는 user_tab_columns라는 dictionary에서 볼 수 있음
-- data_default에서 해당 case문 확인 가능
pivot / unpivot 함수
- pivot()
- row 형태의 데이터를 column 형태로 보여주는 쿼리를 row-to-column
- unpivot()
- column 형태를 row 형태로 보여주는 쿼리를 column-to-row
DECODE
를 이용하여 복잡한 조건식 평가나 여러 칼럼을 이용한 조건식을 평가해야 하는 경우, 문장의 복잡성과 성능에 문제점을 가질 수 있다.
이를 11g 부터는 PIVOT
과 UNPIVOT
절을 통해서 보다 쉽게 구현할 수 있다.
SELECT department_id,
SUM(DECODE(job_id, 'IT_PROG', salary)) "IT MAN",
SUM(DECODE(job_id, 'SA_REP', salary)) "SALES MAN",
SUM(DECODE(job_id, 'ST_CLERK', salary)) "STOCK MAN"
FROM employees
GROUP BY department_id;
-- 위는 아래와 같다.
SELECT *
FROM (SELECT department_id, job_id, salary
FROM employees)
PIVOT (SUM(salary) FOR job_id IN ('IT_PROG' AS "IT MAN"
, 'SA_REP' AS "SALES MAN"
, 'ST_CLERK' AS "STOCK MAN"));
DEPARTMENT_ID | IT MAN | SALES MAN | STOCK MAN | |
---|---|---|---|---|
1 | (null) | (null) | 7000 | (null) |
2 | 90 | (null) | (null) | (null) |
3 | 20 | (null) | (null) | (null) |
4 | 110 | (null) | (null) | (null) |
5 | 50 | (null) | (null) | 11700 |
- 예시 1 : 부서 별 사원수 집계 현황
SELECT department_id, COUNT(*)
FROM employees
GROUP BY department_id;
DEPARTMENT_ID | COUNT(*) | |
---|---|---|
1 | 1 | |
2 | 90 | 3 |
3 | 20 | 2 |
4 | 110 | 2 |
5 | 50 | 5 |
6 | 80 | 3 |
7 | 60 | 3 |
8 | 10 | 1 |
SELECT *
FROM (SELECT department_id
FROM employees)
PIVOT (COUNT(*)
FOR (department_id)
IN (10, 20, 50, 60, 80, 90, 110, 190));
10 | 20 | 50 | 60 | 80 | 90 | 110 | 190 | |
---|---|---|---|---|---|---|---|---|
1 | 1 | 2 | 5 | 3 | 3 | 3 | 2 | 0 |
- 예시 2 : 사원의 월 별 급여 집계
SELECT * FROM
(SELECT '1월' 월, '이태정' 성명, 110 급여 FROM DUAL UNION ALL
SELECT '1월' 월, '이태정' 성명, 305 급여 FROM DUAL UNION ALL
SELECT '1월' 월, '이태서' 성명, 210 급여 FROM DUAL UNION ALL
SELECT '2월' 월, '이태정' 성명, 120 급여 FROM DUAL UNION ALL
SELECT '2월' 월, '이태서' 성명, 220 급여 FROM DUAL)
PIVOT (SUM(급여) FOR 월 IN ('1월', '2월'));
SELECT * FROM
( SELECT '이태정' 성명, 140 일월, 120 이월 FROM DUAL UNION ALL
SELECT '이태서' 성명, 210 일월, 220 이월 FROM DUAL)
UNPIVOT (급여 FOR 월 IN (일월, 이월));
성명 | ‘1월’ | ‘2월’ | |
---|---|---|---|
1 | 이태정 | 415 | 120 |
2 | 이태서 | 210 | 220 |
성명 | 월 | 급여 | |
---|---|---|---|
1 | 이태정 | 일월 | 140 |
2 | 이태정 | 이월 | 120 |
3 | 이태서 | 일월 | 210 |
4 | 이태서 | 이월 | 220 |