본문 바로가기
Daily/디지털하나로

SQL 이론&실습

by HANNI하니 2023. 6. 13.

SQL 이론&실습 230518~230522

1. 데이터 모델

2. SQL (Structured Query Language)

3. 데이터 조회 DQL

4. 함수

 

 

 

1. 데이터 모델

데이터베이스 = 데이터 + 베이스(맨 아래 부분, 기초, 토대, 근거지, 본부 본사 등)

DBMS(Database Management System) = 데이터베이스 관리 시스템

데이터 = 사전적) 자료,정보 / 원자료,원석

 

데이터 모델 (컴퓨터에 데이터를 저장하는 방식을 정의해 놓은 개념 모형)

1. 계층형

나뭇가지 형태의 트리 구조를 활용

데이터 관련성을 계층별로 나누어 부모 자식 같은 관계를 정의하고 데이터 관리

일대다 관계의 데이터 구조

부모가 여러 자식을 가질 수 있지만 자식이 여러 부모를 가질 수 없음

 

2. 네트워크형 = 망형

그래프 구조를 기반

개체 간 관계를 그래프 구조로 연결하여 자식이 여러 부모를 가질 수 있음

 

------- 1960년대 말부터 1980년대 말까지 상업용 데이터베이스 시장에서 많이 사용함

 

3. 관계형 Realtional ★

1970년대 에드거 프랭크 커드가 제안한 모델

현대(1980년대 후반부터 지금)에 가장 많이 사용하는 관계형 데이터베이스의 바탕이 되는 모델

다른 모델과 달리 데이터 간 관계에 초점을 둠

예) 회사의 사원 정보와 소속된 부서 정보를 함께 관리하면 같음 부서의 사원들의 부서 정보는 중복됨, 부서 이름이 바뀌면 모두 찾아서 변경해줘야 함

관계형 데이터베이스 관리 시스템 RDBMS

MS-SQL, MySQL, MariaDB, PostgreSQL, DB2, Oracle 등

 

4. 객체 지향형

1980년대 후반에 등장한 모델

데이터를 독립된 객체로 구성, 관리, 상속, 오버라이드 등의 기능 활용

데이터베이스에 적용하는 것은 쉽지 않음

하지만 오라클 객체 관계형 DBMS  영역을 확장하고 있음

 

2. SQL (Structured Query Language)

데이터베이스를 다루고 관리하는 데 사용하는 데이터베이스 질의 언어

데이터에 관해 물어보고 결과를 얻는다. (대화)

DQL : 데이터 조회

DML : 데이터 저장, 수정, 삭제

DDL : 객체 생성, 수정, 삭제

TCL : 트랜젝션 데이터 SQL 물음

DCL : 데이터 사용 권한

 

관계형 데이터베이스의 구성 요소

테이블(행=ROW=TUPLE=RECORD/열=COLUMN=ATTRIBUTE=FIELD) : 행과 열의 특성에 맞춰 데이터를 저장한 테이블 하나하나가 관계형 데이터베이스의 관계, 여러 테이블의 구성과 관계를 잘 규정하고 관리하는 것이 데이터 관리의 핵심

키 : 수많은 데이터를 구별할 수 있는 유일한 값, 데이터를 구별하거나 테이블 간의 연관관계를 표현할 때 키로 지정한 열을 사용

 

키 종류

기본키 : 가장 중요한 키

한 테이블 내에서 중복되지 않는 값만 가질 수 있는 키

유일한 값 & 중복 없음 & NULL 값 없음

보조키 = 대체키 : 후보키(기본키가 될 수 있는 조건 만족하는 열)에 속해 있는 키, 기본키를 제외한 나머지

외래키 : 특정 테이블에 포함되어 있으면서 다른 테이블의 기본 키로 지정된 키

복합키 : 여러 열을 조합하여 기본 키 역할을 할 수 있게 만든 키, 하나의 열만으로 행을 식별하는 것이 불가능하기 때문, 두 개 이상의 열을 조합해야만 각 행이 유일한 데이터로서 가치를 지님

 

객체 : 테이블, 인덱스, 뷰, 시퀀스, 시노님, 프로시저, 함수, 패키지, 트리거

PL/SQL : 데이터 관리를 위한 별도의 프로그래밍 언어, 데이터 관리를 하기 위해 복잡한 기능이 필요할 때 기존의 SQL만으로는 한계 있음, 변수,조건문,반복문 등 프로그래밍 언어에서 제공하는 요소들을 사용하여 데이터를 관리할 수 있음

 

3. 데이터 조회 DQL

SQL 작성 규칙 : 대소문자를 구분하지 않기 때문에 대문자로 작성

프로그래밍 언어는 소문자로 작성, 쿼리(SQL)는 대문자로 작성, 프로그래밍 언어와 쿼리 언어를 같이 작성하는 경우 구분이 쉬움

 

SELECTION 셀렉션 : 행 단위로 원하는 데이터 조회

PROJECTION 프로젝션 : 열 단위로 원하는 데이터 조회

JOIN 조인 : 두 개 이상의 테이블을 사용하여 하나의 테이블처럼 데이터 조회

 

3.1. SELECT ~ FROM ~

-- 주석 ctrl +/
-- 실습에 사용할 테이블 구조 보기
DESC EMP;
-- 부서 테이블
DESC DEPT;
-- 급여등급 테이블
DESC SALGRADE;
--
-- SQL 기본
-- SELECT 열 FROM 테이블명
SELECT * FROM EMP;
-- 사원 이름 보기
-- 한 개의 열만 보기 = 프로젝션
SELECT ENAME FROM EMP;
-- 사원 이름 & 직책 보기 : 쉼표로 여러 열 나열
SELECT ENAME, JOB FROM EMP;
-- 부서 테이블 전체 보기
-- 행 4 * 열 3
SELECT * FROM DEPT;
-- 부서 이름 보기 = 프로젝션
SELECT DNAME FROM DEPT;
-- 부서 이름 & 부서 위치 보기
SELECT DNAME, LOC FROM DEPT;
-- 중복 제거 DISTINCT
SELECT DEPTNO FROM EMP;
SELECT DISTINCT DEPTNO FROM EMP;
SELECT DISTINCT JOB,DEPTNO FROM EMP;
-- 별칭 설정
SELECT ENAME, SAL, SAL*12+COMM FROM EMP;
SELECT ENAME, SAL, SAL*12+COMM AS ANNSAL FROM EMP; -- 별칭 설정하여 공개하기 싫은 계산식 숨길 수 있음
SELECT ENAME, SAL, SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+COMM FROM EMP; -- 나오는 열 이름이 너무 길어서 별칭을 설정하면 짧게 나오게 할 수 있음
SELECT ENAME, SAL, SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+SAL+COMM AS ANNSAL FROM EMP;
-- 정렬하기
-- 오름차순 ASC (생략가능=디폴트)
-- 급여가 낮은 값에서 높은 값으로 정렬
SELECT * FROM EMP ORDER BY SAL ASC;
SELECT * FROM EMP ORDER BY SAL;
-- 내림차순 DESC
-- 급여가 높은 값에서 낮은 값으로 정렬
SELECT * FROM EMP ORDER BY SAL DESC;
-- 두개 이상의 열로 정렬
SELECT * FROM EMP ORDER BY DEPTNO ASC, SAL DESC;

ORDER BY 정렬은 꼭 필요한 경우가 아니라면 사용하지 않는 것이 좋음

정렬하는 시간이 많이 걸리기 때문!

SQL 효율이 낮아진다 = 서비스 응답 시간이 느려진다

 

3.2. SELECT ~ FROM ~ WHERE ~ 필요한 데이터만 조회하기

'문자열' : 작은따옴표 사용

실무에선 AND 연산자를 많이 사용

-- where 절 조건
SELECT * FROM EMP;
-- 30번 부서에 일하는 직원 = 6명
SELECT * FROM EMP WHERE DEPTNO = 30;
-- 사원번호 7782 인 사원
SELECT * FROM EMP WHERE EMPNO = 7782;
-- AND 교집합
SELECT * FROM EMP WHERE DEPTNO = 30 AND JOB = 'SALESMAN';
SELECT * FROM EMP WHERE DEPTNO = 30 AND EMPNO = 7499;
-- OR 합집합
SELECT * FROM EMP WHERE DEPTNO = 30 OR JOB = 'SALESMAN';
SELECT * FROM EMP WHERE DEPTNO = 20 OR JOB = 'SALESMAN';
-- 산술 연산자 = 사칙연산
SELECT * FROM EMP WHERE SAL*12 = 36000;
-- 비교 연산자
SELECT * FROM EMP WHERE SAL >= 3000;
SELECT * FROM EMP WHERE SAL >= 3000 AND JOB = 'ANALYST';
SELECT * FROM EMP WHERE SAL >= 2000 AND JOB = 'ANALYST';
-- 등가 연산자
SELECT * FROM EMP WHERE SAL != 3000;
SELECT * FROM EMP WHERE SAL = 3000;
-- NOT 논리정연산자
SELECT * FROM EMP WHERE NOT SAL = 3000;
-- IN 연산자 = OR 조건 여러개
SELECT * FROM EMP WHERE JOB IN ('MANAGER','SALESMAN','CLERK');
SELECT * FROM EMP WHERE JOB = 'MANAGER' OR JOB = 'SALESMAN' OR JOB = 'CLERK';
-- NOT IN 연산자
SELECT * FROM EMP WHERE JOB NOT IN ('MANAGER','SALESMAN','CLERK');
SELECT * FROM EMP WHERE JOB != 'MANAGER' AND JOB != 'SALESMAN' AND JOB != 'CLERK';
-- 10번, 20번 부서에서 근무하는 직원 =>  IN
SELECT * FROM EMP WHERE DEPTNO IN (10,20);
-- 10번 부서에서 근무하는 직운 => NOT IN
SELECT * FROM EMP WHERE DEPTNO NOT IN 10;
-- BETWEEN A AND B = A보다 크거나 같고, B보다 작거나 같다
SELECT * FROM EMP WHERE SAL BETWEEN 2000 AND 3000;
SELECT * FROM EMP WHERE SAL >= 2000 AND SAL <= 3000;
-- NOT BETWEEN A AND B = A보다 작거나, B보다 크다
SELECT * FROM EMP WHERE SAL NOT BETWEEN 2000 AND 3000;
SELECT * FROM EMP WHERE SAL < 2000 OR SAL > 3000;

 

3.3. LIKE 연산자 & 와일드 카드

% 길이와 상관없이(문자 없는 경우도 포함) 모든 문자 데이터를 의미

_ 어떤 값이든 상관없이 한 개의 문자 데이터를 의미

와일드카드를 어떻게 사용하느냐에 따라 조회 시간에 차이가 있음

-- LIKE 연산자 & 와일드카드
-- S로 시작하는 이름을 가진 모든 사원
SELECT * FROM EMP WHERE ENAME LIKE 'S%';
-- 두번째 글자가 L인 이름을 가진 모든 사원
SELECT * FROM EMP WHERE ENAME LIKE '_L%';
-- 이름에 S가 있는 이름을 가진 모든 사원
SELECT * FROM EMP WHERE ENAME LIKE '%S%';
-- 이름에 AM이 있는 모든 사원
SELECT * FROM EMP WHERE ENAME LIKE '%AM%';
-- IS NULL 연산자
SELECT ENAME,SAL,SAL*12+COMM AS ANNSAL, COMM FROM EMP;
SELECT * FROM EMP WHERE COMM = NULL;  -- 널값 찾을 수 없음
SELECT * FROM EMP WHERE COMM IS NULL; -- 널값 찾을 수 있음
SELECT * FROM EMP WHERE COMM IS NOT NULL;
-- 직속상관이 있는 사람과 없는 사람
SELECT * FROM EMP WHERE MGR IS NOT NULL;
SELECT * FROM EMP WHERE MGR IS NULL;
-- NULL을 이용한 AND / OR 연산
-- AND 조건은 둘 다 참이어야 하는, 이 경우 앞의 조건이 무조건 NULL 이므로 성립이 안됨
SELECT * FROM EMP WHERE SAL > NULL AND COMM IS NULL;
-- OR 조건은 둘 중의 하나만 참이어도 성립, 이 경우 뒤의 조건이 참인 경우가 있음 = 수당이 널값인 사람
SELECT * FROM EMP WHERE SAL > NULL OR COMM IS NULL;
SELECT * FROM EMP WHERE COMM IS NULL;

 

3.4. UNION 중복 제거 합집합

첫번째, 두번째 SELECT 절의 열 이름&순서 모두 동일해야 함

UNION ALL 중복 제거 없이 합집합

MINUS 차집합

INTERSECT 교집합

-- 집합 연산자 UNION
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10
UNION
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 20;
-- 중복 제거 확인
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10
UNION
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10;
-- UNION ALL 중복 제거 없이 합집합
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10
UNION ALL
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10;
-- 합집합 사용할 때 주의할 점 확인
-- 1) 두 번째 테이블의 DEPTNO 빼고 합치기 => 열의 개수 맞아야 함
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10
UNION
SELECT EMPNO, ENAME, SAL FROM EMP WHERE DEPTNO = 20;
-- 2) 열의 순서를 바꿔서 합치기 + 데이터 타입이 다르게 => 서로 데이터 타입이 같아야 함
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10
UNION
SELECT ENAME, EMPNO, SAL FROM EMP WHERE DEPTNO = 20;
-- 3)열의 순서를 바꿔서 합치기 + 데이터 타입이 같게 => 잘못 합쳐진 것이니 열의 순서를 똑같이 맞춰야 함
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10
UNION
SELECT SAL, ENAME, DEPTNO, EMPNO FROM EMP WHERE DEPTNO = 20;
-- MINUS 차집합
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP
MINU
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10;
-- INTERSECT 교집합
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP
INTERSECT
SELECT EMPNO, ENAME, SAL, DEPTNO FROM EMP WHERE DEPTNO = 10;

연산자 우선순위 높음->낮음

*, /

+, -

=, !=, ^=, <>, >, >=, <, <=

IS (NOT) NULL, (NOT) LIKE, (NOT) IN

BETWEEN A AND B

NOT

AND

OR

 

4. 함수

내장함수 : 이미 만들어져 있는 함수

-> 단일행 함수 (행마다 결과가 나오는 함수) / 다중행 함수 (하나의 행으로 결과가 나오는 함수)

사용자 정의 함수 : 사용자가 직접 만들어야 하는 함수

--함수
--내장함수
--문자열 관련 함수
--대문자, 소문자, 첫글자만 대문자 나머지 소문자로 변경
SELECT ENAME, UPPER(ENAME), LOWER(ENAME), INITCAP(ENAME) FROM EMP;
--응용
SELECT * FROM EMP WHERE ENAME = 'SCOTT';
SELECT * FROM EMP WHERE UPPER(ENAME) = 'SCOTT';
SELECT * FROM EMP WHERE LOWER(ENAME) = 'scott';
SELECT * FROM EMP WHERE LOWER(ENAME) LIKE 's%';

UPPER() 대문자로 바꾸기

LOWER() 소문자로 바꾸기

INITCAP()  첫글자만 대문자, 나머지는 소문자로 바꾸기

LENGTH() 문자열 길이

LENGTHB() 문자열 바이트 수

SUBSTR(문자열,시작위치,끝위치) 문자열 일부 추출

INSTR(문자열,특정문자) 특정 문자의 위치

REPLACE(문자열,특정문자,다른문자) 특정 문자를 다른 문자로 바꾸기

LPAD(문자열,총자릿수,특정문자) 왼쪽부터 특정 문자로 채우기

RPAD(문자열,총자릿수,특정문자) 오른쪽부터 특정 문자로 채우기

CONCAT(합칠문자,합칠문자열) 문자열 합치기 = ||

--문자열 길이
SELECT ENAME, LENGTH(ENAME) FROM EMP;
SELECT ENAME, LENGTH(ENAME) FROM EMP WHERE LENGTH(ENAME) >= 5;
SELECT ENAME, LENGTH(ENAME) FROM EMP WHERE LENGTH(ENAME) < 5;
--문자열 바이트
--DUAL: 관리자 계정 SYS 소유 테이블, 함수 기능이나 연산 등 테스트 목적으로 사용하는 가상 테이블
SELECT LENGTH('HELLO'), LENGTHB('HELLO') FROM DUAL;
SELECT LENGTH('안녕'), LENGTHB('안녕') FROM DUAL;
--문자열 일부 추출
--첫 번째 숫자: 시작 위치, 두 번째 숫자: 글자 수 (생략하면 끝까지)
SELECT JOB, SUBSTR(JOB, 1, 2) FROM EMP; -- 2글자
SELECT JOB, SUBSTR(JOB, 3, 5) FROM EMP; -- 5글자
SELECT JOB, SUBSTR(JOB, 3) FROM EMP; -- 시작위치부터 끝까지
--응용, 글자수를 예측하기 어려울 때 LENGTH()
--LENGTH('CLERK') : 1 ~ 5
SELECT JOB, LENGTH(JOB) FROM EMP;
--처음부터 끝까지
---LENGTH('CLERK') : -5 ~ -1
SELECT JOB, SUBSTR(JOB, -LENGTH(JOB)) FROM EMP;
SELECT JOB, SUBSTR(JOB, -LENGTH(JOB), 2) FROM EMP;
--뒤에서 찾고 싶을 때
SELECT JOB, SUBSTR(JOB, LENGTH(JOB)) FROM EMP; -- 뒤에서부터 1글자
SELECT JOB, SUBSTR(JOB, LENGTH(JOB)-1) FROM EMP; -- 뒤에서부터 2글자
SELECT JOB, SUBSTR(JOB, LENGTH(JOB)-2) FROM EMP; -- 뒤에서부터 3글자
SELECT JOB, SUBSTR(JOB, LENGTH(JOB)-3) FROM EMP; -- 뒤에서부터 4글자
--특정 문자 위치
SELECT INSTR('HELLO, ORACLE!','L'), -- L 글자가 처음 나타나는 위치
       INSTR('HELLO, ORACLE!','L',5), -- 5번째부터 L 글자가 처음 나타나는 위치
       INSTR('HELLO, ORACLE!','L',2,2) -- 2번째부터 L 글자가 두번째 나타나는 위치
    FROM DUAL;
--다른 문자로 대체
SELECT '010-1234-5678',
       REPLACE('010-1234-5678', '-', ' '), -- 대시(-) 기호를 BLANK 로 대체
       REPLACE('010-1234-5678', '-', '*'), -- 대시(-) 기호를 * 로 대체
       REPLACE('010-1234-5678', '-') -- 대시(-) 기호를 ''로 대체 = 삭제
    FROM DUAL;
--빈칸을 특정 문자로 채우기
--LPAD: LEFT 에서 채움
--RPAD: RIGHT 에서 채움
SELECT 'Oracle',
       LPAD('Oracle', 10, '#'), -- 10자리, Oracle 글자를 오른쪽부터 넣고, 남은자리를 왼쪽에서 # 채움
       RPAD('Oracle', 10, '*'), -- 10자리, Oracle 글자를 왼쪽부터 넣고, 남은자리를 오른쪽에서 # 채움
       LPAD('Oracle', 10), -- 10자리, Oracle 글자를 오른쪽부터 넣고, 남은자리를 왼쪽에서 BLANK 채움
       RPAD('Oracle', 10) -- 10자리, Oracle 글자를 왼쪽부터 넣고, 남은자리를 오른쪽에서 BLANK 채움
    FROM DUAL;
--문자열 합치기 CONCAT
SELECT EMPNO, ENAME FROM EMP WHERE ENAME = 'SCOTT';
SELECT CONCAT(EMPNO, ENAME) FROM EMP WHERE ENAME = 'SCOTT';
SELECT CONCAT(':',ENAME), CONCAT(EMPNO, CONCAT(':',ENAME)) FROM EMP WHERE ENAME = 'SCOTT';
--|| 로 변환
SELECT EMPNO || ENAME FROM EMP WHERE ENAME = 'SCOTT';
SELECT ':' || ENAME, EMPNO || ':' || ENAME FROM EMP WHERE ENAME = 'SCOTT';

 

TRIM() 특정문자 지우기 LTRIM/RTRIM

--특정 문자를 지우는 함수
--TRIM = 앞뒤 = TRIM BOTH FROM
--LTRIM = 앞 = 왼쪽 = TRIM LEADING FROM
--RTRIM = 뒤 = 오른쪽 = TRIM TRAILING FROM
--어떤 문자를 지울지 정하지 않으면 공백 제거
SELECT '['||' _ _Oracle_ _ '||']',
       '['||TRIM(' _ _Oracle_ _ ')||']', -- = TRIM => [_ _Oracle_ _]
       '['||TRIM(BOTH FROM ' _ _Oracle_ _ ')||']', -- = TRIM => [_ _Oracle_ _]
       '['||TRIM(LEADING FROM ' _ _Oracle_ _ ')||']', -- = LTRIM => [_ _Oracle_ _ ]
       '['||TRIM(TRAILING FROM ' _ _Oracle_ _ ')||']' -- = RTRIM => [ _ _Oracle_ _]
    FROM DUAL;
--TRIM, LTRIM, RTRIM 함수로 바꿔서 그대로 재현
SELECT '['||' _ _Oracle_ _ '||']',
       '['||TRIM(' _ _Oracle_ _ ')||']', -- = TRIM => [_ _Oracle_ _]
       '['||LTRIM(' _ _Oracle_ _ ')||']', -- = LTRIM => [_ _Oracle_ _ ]
       '['||RTRIM(' _ _Oracle_ _ ')||']' -- = RTRIM => [ _ _Oracle_ _]
    FROM DUAL;
--지우고 싶은 문자 지정해서 사용
SELECT '['||'_ _Oracle_ _'||']',
       '['||TRIM('_ _Oracle_ _')||']', -- = TRIM => [_ _Oracle_ _]
       '['||TRIM(BOTH '_' FROM '_ _Oracle_ _')||']', -- = TRIM => [ _Oracle_ ]
       '['||TRIM(LEADING '_' FROM '_ _Oracle_ _')||']', -- = LTRIM => [ _Oracle_ _ ]
       '['||TRIM(TRAILING '_' FROM '_ _Oracle_ _')||']' -- = RTRIM => [ _ _Oracle_ ]
    FROM DUAL;
--TRIM, LTRIM, RTRIM 함수로 바꿔서 그대로 재현
SELECT '['||'_ _Oracle_ _'||']',
       '['||TRIM('_ _Oracle_ _')||']', -- = TRIM => [_ _Oracle_ _]
       '['||LTRIM('_ _Oracle_ _', '_')||']', -- = LTRIM => [ _Oracle_ _ ]
       '['||RTRIM('_ _Oracle_ _', '_')||']' -- = RTRIM => [ _ _Oracle_ ]
    FROM DUAL;

 

숫자 함수

ROUND() 반올림

TRUNC() 버리기

CEIL() 올림

FLOOR() 내림

MOD() 나머지값

--
--숫자함수
--반올림, 소수점 이하에서 표현할 자리수
SELECT ROUND(1234.5678),
       ROUND(1234.5678, 0),
       ROUND(1234.5678, 1),
       ROUND(1234.5678, 2),
       ROUND(1234.5678, -1),
       ROUND(1234.5678, -2)
    FROM DUAL;
--버리기
SELECT TRUNC(1234.5678),
       TRUNC(1234.5678, 0),
       TRUNC(1234.5678, 1),
       TRUNC(1234.5678, 2),
       TRUNC(1234.5678, -1),
       TRUNC(1234.5678, -2)
    FROM DUAL;
--정수 반환 함수
--CEIL = 천장 = 높은 정수값, 3 < 3.14 < 4
--FLOOR = 바닥 = 낮은 정수값, 3 < 3.14 < 4
--CEIL = 천장 = 높은 정수값, -4 < -3.14 < -3
--FLOOR = 바닥 = 낮은 정수값, -4 < -3.14 < -3
SELECT CEIL(3.14),
       FLOOR(3.14),
       CEIL(-3.14),
       FLOOR(-3.14)
    FROM DUAL;
--나머지
SELECT MOD(15, 6), --15/6 = 몫 2 나머지 3
       MOD(10, 2), --10/2 = 몫 5 나머지 0
       MOD(11, 2) --11/2 = 몫 5 나머지 1
    FROM DUAL;

 

날짜 함수

SYSDATE 현재 날짜와 시간

ADD_MONTH(기준날짜,추가개월수) 특정 개월 이후 날짜

MONTH_BETWEEN(기준날짜,개월수) 특정 개월 수 차이

NEXT_DAY() 돌아오는 요일의 날짜

LAST_DAY() 특정 월의 마지막 날짜

--날짜함수
--현재 날짜
SELECT SYSDATE FROM DUAL;
SELECT SYSDATE - 1 FROM DUAL;
SELECT SYSDATE + 1 FROM DUAL;
SELECT SYSDATE + 100 FROM DUAL;
--특정 개월 후의 날짜
SELECT SYSDATE, ADD_MONTHS(SYSDATE, 3) FROM DUAL;
SELECT SYSDATE, ADD_MONTHS(SYSDATE, 120) FROM DUAL;
--입사 10주년
SELECT ENAME, HIREDATE, ADD_MONTHS(HIREDATE, 120) FROM EMP;
--과거 날짜 작은 값
--미래날짜 큰 값
--내일은 오늘보다 큰 값
--입사 41주년 미만 = 입사일 41주년 > 현재날짜 = 미래날짜 > 현재날짜
SELECT ENAME, HIREDATE, ADD_MONTHS(HIREDATE, 492), SYSDATE 
    FROM EMP 
   WHERE ADD_MONTHS(HIREDATE, 492) > SYSDATE;
--입사 41주년 초과 = 입사일 41주년 < 현재날짜 = 과거날짜 < 현재날짜
SELECT ENAME, HIREDATE, ADD_MONTHS(HIREDATE, 492), SYSDATE 
    FROM EMP 
   WHERE ADD_MONTHS(HIREDATE, 492) < SYSDATE;
--개월수 차이
SELECT EMPNO, ENAME, HIREDATE, SYSDATE,
       MONTHS_BETWEEN(HIREDATE, SYSDATE), --과거날짜 - 현재날짜 = 작은값 - 큰값 = 음수(우리가 원하는 결과 아님)
       MONTHS_BETWEEN(SYSDATE, HIREDATE), --현재날짜 - 과거날짜 = 큰값 - 작은값 = 양수(우리가 원하는 결과)
       TRUNC(MONTHS_BETWEEN(SYSDATE, HIREDATE)) -- 소수점 첫째자리 이하 버림 = 정수 형태
    FROM EMP;
--돌아오는 요일의 날짜
--해당 월의 마지막 날짜
SELECT SYSDATE, NEXT_DAY(SYSDATE, '수요일'), LAST_DAY(SYSDATE) FROM DUAL;
--날짜 반올림 = 중앙값을 찾아라
SELECT SYSDATE,
       ROUND(SYSDATE, 'CC'), --세기(100년)의 중앙값 51년 이상 반올림 2001
       ROUND(SYSDATE, 'YYYY'), --연도(1년)의 중앙값 7월 1일부터 반올림 23-01-01
       ROUND(SYSDATE, 'Q'), --분기(3개월)의 중앙값은 중앙에 있는 달의 16일부터 23-07-01
       ROUND(SYSDATE, 'DDD'), --일(하루)의 중앙값은 12시부터 23-05-20
       ROUND(SYSDATE, 'HH') --시간(60분)의 중앙값은 31분부터 23-05-19
    FROM DUAL;
--날짜 버리기
SELECT SYSDATE,
       TRUNC(SYSDATE, 'CC'),
       TRUNC(SYSDATE, 'YYYY'),
       TRUNC(SYSDATE, 'Q'),
       TRUNC(SYSDATE, 'DDD'),
       TRUNC(SYSDATE, 'HH')
    FROM DUAL;

 

형 변환 함수

TO_CHAR(기준날짜,'MM')

TO_NUMBER('1500','999,999')

TO_DATE('2023-05-19','YYYY/MM/DD')

--형 변환 함수
--암시적 형 변환 = 문자 => 숫자로 자동으로 바꿔줌
SELECT EMPNO, EMPNO + '1000' FROM EMP;
--1,000 는 문자 = 숫자 변환 불가 = 에러 발생
SELECT EMPNO, EMPNO + '1,000' FROM EMP;
--명시적 형 변환
--문자 형 변환
--날짜를 문자로 변환
SELECT SYSDATE FROM EMP;
--날짜 시간 포맷 입력해야 함
--연월일은 / 로 연결
--시분초는 : 으로 연결
SELECT SYSDATE, TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') FROM EMP;
--월 일 요일
SELECT SYSDATE,
       TO_CHAR(SYSDATE, 'MM'), --숫자 월
       TO_CHAR(SYSDATE, 'MON'), --이름 월, 약자
       TO_CHAR(SYSDATE, 'MONTH'), --이름 월, FULL NAME
       TO_CHAR(SYSDATE, 'DD'), -- 숫자 일
       TO_CHAR(SYSDATE, 'DY'), -- 이름 요일, 약자
       TO_CHAR(SYSDATE, 'DAY') -- 이름 요일, FULL NAME
    FROM DUAL;
--
SELECT SYSDATE,
       TO_CHAR(SYSDATE, 'MM'),
       TO_CHAR(SYSDATE, 'MON', 'NLS_DATE_LANGUAGE = KOREAN'),
       TO_CHAR(SYSDATE, 'MON', 'NLS_DATE_LANGUAGE = JAPANESE'),
       TO_CHAR(SYSDATE, 'MON', 'NLS_DATE_LANGUAGE = ENGLISH'),
       TO_CHAR(SYSDATE, 'MONTH', 'NLS_DATE_LANGUAGE = KOREAN'),
       TO_CHAR(SYSDATE, 'MONTH', 'NLS_DATE_LANGUAGE = JAPANESE'),
       TO_CHAR(SYSDATE, 'MONTH', 'NLS_DATE_LANGUAGE = ENGLISH')
    FROM DUAL;
SELECT SYSDATE,
       TO_CHAR(SYSDATE, 'DD'),
       TO_CHAR(SYSDATE, 'DY', 'NLS_DATE_LANGUAGE = KOREAN'),
       TO_CHAR(SYSDATE, 'DY', 'NLS_DATE_LANGUAGE = JAPANESE'),
       TO_CHAR(SYSDATE, 'DY', 'NLS_DATE_LANGUAGE = ENGLISH'),
       TO_CHAR(SYSDATE, 'DAY', 'NLS_DATE_LANGUAGE = KOREAN'),
       TO_CHAR(SYSDATE, 'DAY', 'NLS_DATE_LANGUAGE = JAPANESE'),
       TO_CHAR(SYSDATE, 'DAY', 'NLS_DATE_LANGUAGE = ENGLISH')
    FROM DUAL;
--시분초
SELECT SYSDATE, TO_CHAR(SYSDATE, 'HH24:MI:SS'), --24시간
                TO_CHAR(SYSDATE, 'HH12:MI:SS'), --12시간
                TO_CHAR(SYSDATE, 'HH12:MI:SS PM'), --12시간, 오전/오후
                TO_CHAR(SYSDATE, 'HH:MI:SS PM') --12시간, 오전/오후
    FROM DUAL;
--숫자 형식
--숫자를 문자로 변환
SELECT SAL, --숫자 월급
       TO_CHAR(SAL, '$999,999'), --$ & 천단위 , 구분
       TO_CHAR(SAL, 'L999,999'), --LOCAL 통화량 = 한국 원 & 천단위 , 구분
       TO_CHAR(SAL, '999,999.00'), --소수점 두자리 & 숫자로만 표현
       --총 11자리 = 정수 9자리수 & 소수점 두자리, & 천단위 , 구분, 숫자 채우고 남은 자리를 0으로 채움
       TO_CHAR(SAL, '000,999,999.00'), 
       TO_CHAR(SAL, '000999999.99'), --총 11자리 = 정수 9자리수 & 소수점 두자리
       TO_CHAR(SAL, '999,999,00')
    FROM EMP;
--숫자 형 변환
--암시적 형 변환 = 문자를 숫자로 변환 = TO_NUMBER 함수 사용하지 않음
SELECT 1300 - '1500', '1300' + 1500 FROM DUAL;
--명시적 형 변환
SELECT 1300 - TO_NUMBER('1500'), TO_NUMBER('1300') + 1500 FROM DUAL;
--TO_NUMBER 함수를 사용하여 문제 해결
SELECT '1,300' - '1,500' FROM DUAL;
SELECT TO_NUMBER('1,300', '999,999') - TO_NUMBER('1,500', '999,999') FROM DUAL;
--날짜 형 변환
SELECT TO_DATE('2023-05-19', 'YYYY/MM/DD') FROM DUAL;
SELECT TO_DATE('20230519', 'YYYY/MM/DD') FROM DUAL;
SELECT TO_DATE('2023-05-19', 'YYYY-MM-DD') FROM DUAL;
SELECT TO_DATE('20230519', 'YYYY-MM-DD') FROM DUAL;
SELECT TO_DATE('2023/05/19', 'YYYY-MM-DD') FROM DUAL;
SELECT TO_DATE('2023/05/19', 'YYYY/MM/DD') FROM DUAL;
--사원 데이터에서 81년 7월 1일 이후에 입사한 사람
SELECT * FROM EMP WHERE HIREDATE > TO_DATE('1981-07-01', 'YYYY-MM-DD');
--사원 데이터에서 81년 7월 1일 이전에 입사한 사람
SELECT * FROM EMP WHERE HIREDATE < TO_DATE('1981-07-01', 'YYYY-MM-DD');
--RR: 1950~2049
SELECT TO_DATE('49/12/10', 'YY/MM/DD') AS Y1, --2049
       TO_DATE('49/12/10', 'RR/MM/DD') AS Y2, --2049
       TO_DATE('50/12/10', 'YY/MM/DD') AS Y3, --2050
       TO_DATE('50/12/10', 'RR/MM/DD') AS Y4, --1950
       TO_DATE('51/12/10', 'YY/MM/DD') AS Y5, --2051
       TO_DATE('51/12/10', 'RR/MM/DD') AS Y6 --1951
    FROM DUAL;

 

널 처리 함수

NVL(칼럼명,NULL이면 대체) NULL 아니면 원래 값

NVL2(칼럼명,NULL이면 대체, NULL 아니면 출력값)

 

상황에 따라 다른 데이터 반환하는 함수

DECODE() 같다는 조건만 가능

CASE() 같다는 조건 말고도 가능

--널 처리 함수
--NVL 함수: 널값일 때 내가 원하는 값으로 변경, 나머지는 그대로
SELECT EMPNO, ENAME, SAL, COMM, SAL+COMM, NVL(COMM, 0), SAL+NVL(COMM, 0) FROM EMP;
--NVL2 함수
--첫번째 매개변수-널값이 아닐 때 내가 원하는 값으로 변경
--두번째 매개변수-널값일 때 내가 원하는 값으로 변경
SELECT EMPNO, ENAME, SAL, COMM, NVL2(COMM, 'O', 'X'), NVL2(COMM, SAL*12+COMM, SAL*12) FROM EMP;
--상황에 따라서 다른 데이터 반환
--DECODE: 같다는 조건만 가능
SELECT DISTINCT JOB FROM EMP;
SELECT EMPNO, ENAME, JOB, SAL,
       DECODE(JOB,
              'MANAGER', SAL*1.1,
              'SALESMAN', SAL*1.05,
              'ANALYST', SAL,
              SAL*1.03) AS UPSAL
    FROM EMP;
--CASE: 같다는 조건 말고도 가능
--앞의 DECODE 문을 CASE 문으로 재현
SELECT EMPNO, ENAME, JOB, SAL,
       CASE JOB
        WHEN 'MANAGER' THEN SAL*1.1
        WHEN 'SALESMAN' THEN SAL*1.05
        WHEN 'ANALYST' THEN SAL
        ELSE SAL*1.03
       END AS UPSAL
    FROM EMP;
--같다는 조건 말고도 사용
SELECT EMPNO, ENAME, COMM,
       CASE 
        WHEN COMM IS NULL THEN '해당 사항 없음'
        WHEN COMM = 0 THEN '수당 없음'
        WHEN COMM > 0 THEN '수당: ' || COMM
       END AS COMM_CMT
    FROM EMP;

 

다중행 함수 = 결과가 하나 = 하나의 값으로 요약

SUM() COUNT() MAX() MIN() AVG()

NULL 값을 자동으로 제외하고 계산함

--다중행 함수 = 결과가 하나 = 하나의 값으로 요약
SELECT SAL FROM EMP;
SELECT SUM(SAL) FROM EMP;
--한 번에 출력하려면 나오는 행의 개수가 같아야 함
SELECT ENAME, SUM(SAL) FROM EMP;
--NULL 값을 자동으로 제외하고 계산
SELECT SUM(COMM) FROM EMP;
--행의 개수가 같으므로 동시 출력이 가능
SELECT SUM(DISTINCT SAL), --중복 제거하여 합
       SUM(ALL SAL), --ALL 쓰지 않아도 결과 동일
       SUM(SAL) --ALL 쓰지 않아도 결과 동일
    FROM EMP;
--다음과 같이 사용하면 됨
SELECT SUM(SAL), SUM(COMM) FROM EMP;
--개수
SELECT COUNT(*) FROM EMP;
SELECT COUNT(*) FROM EMP WHERE DEPTNO = 30;
SELECT COUNT(DISTINCT SAL), --중복 제거하여 카운드
       COUNT(ALL SAL), --ALL 쓰지 않아도 결과 동일
       COUNT(SAL) --ALL 쓰지 않아도 결과 동일
    FROM EMP;
--NULL 값을 자동으로 제외하고 계산
SELECT COUNT(COMM) FROM EMP;
--위와 결과 동일함
SELECT COUNT(COMM) FROM EMP WHERE COMM IS NOT NULL;
--최대값
SELECT MAX(SAL) FROM EMP;
SELECT MAX(SAL) FROM EMP WHERE DEPTNO = 30;
--가장 최근에 (늦게) 입사한 입사일
SELECT MAX(HIREDATE) FROM EMP;
--최소값
SELECT MIN(SAL) FROM EMP;
SELECT MIN(SAL) FROM EMP WHERE DEPTNO = 30;
--가장 오래 전에 (일찍) 입사한 입사일
SELECT MIN(HIREDATE) FROM EMP;
--평균
SELECT AVG(SAL) FROM EMP;
SELECT AVG(SAL) FROM EMP WHERE DEPTNO = 30;
--NULL 값을 자동으로 제외하고 계산
SELECT AVG(COMM) FROM EMP;
SELECT AVG(COMM) FROM EMP WHERE DEPTNO = 30;
--

 

그룹화 함수

GROUP BY ~ HAVING

GROUP BY 절에 지정할 수 있는 특수 함수 = ROLLUP, CUBE, GROUPING SETS

ROLLUP(A,B) = 열의 개수 + 1개의 결과 출력 A+B,A,TOTAL

CUBE(A,B) = 2의 열의 개수 제곱개의 결과 출력 A+B,A,B,TOTAL

GROUPING SETS(A,B) = 열을 따로 그룹화하여 출력 A,B

GROUPING_ID(A,B) = 그룹화 여부의 검사를 열 하나씩 지정하는 GROUPING 함수와 달리 여러 열을 지정할 수 있음

0 0 = 0, 0 1 = 1, 1 0 = 2, 1 1 =3

 

행과 열을 바꿔서 출력 PIVOT()

열을 행으로 바꿔서 출력 UNPIVOT()

--그룹화 함수
--부서 번호 별로 평균 급여 값 출력
--부서 번호 확인
SELECT DISTINCT DEPTNO FROM EMP;
--각 부서 번호에서 근무하는 직원 출력
SELECT * FROM EMP WHERE DEPTNO = 10;
SELECT * FROM EMP WHERE DEPTNO = 20;
SELECT * FROM EMP WHERE DEPTNO = 30;
--각 부서 번호에서 근무하는 직원들의 평균 급여 출력
SELECT AVG(SAL) FROM EMP WHERE DEPTNO = 10;
SELECT AVG(SAL) FROM EMP WHERE DEPTNO = 20;
SELECT AVG(SAL) FROM EMP WHERE DEPTNO = 30;
--집합연산자 UNION / UNION ALL 사용하여 함께 출력
SELECT '10' AS DEPTNO, AVG(SAL) FROM EMP WHERE DEPTNO = 10
UNION
SELECT '20' AS DEPTNO, AVG(SAL) FROM EMP WHERE DEPTNO = 20
UNION
SELECT '30' AS DEPTNO, AVG(SAL) FROM EMP WHERE DEPTNO = 30;
--GROUP BY 절을 이용하여 재현
SELECT DEPTNO, AVG(SAL) FROM EMP GROUP BY DEPTNO;
SELECT DEPTNO, AVG(SAL) FROM EMP GROUP BY DEPTNO ORDER BY DEPTNO;
SELECT DEPTNO, AVG(SAL) FROM EMP GROUP BY DEPTNO ORDER BY DEPTNO ASC;
--2개의 열을 이용하여 GROUP BY
SELECT DEPTNO, JOB, AVG(SAL) FROM EMP GROUP BY DEPTNO, JOB;
SELECT DEPTNO, JOB, AVG(SAL) FROM EMP GROUP BY DEPTNO, JOB ORDER BY DEPTNO ASC, JOB ASC;
--GROUP BY 에 사용하는 열 이름을 SELECT 절에서도 동일하게 사용
--GROUP BY 에 사용하지 않는 열 이름을 SELECT 절에서 사용하게 되면 오류 발생
SELECT DEPTNO, ENAME, AVG(SAL) FROM EMP GROUP BY DEPTNO;
--GROUP BY ~ HAVING (조건)
SELECT DEPTNO, JOB, AVG(SAL) FROM EMP GROUP BY DEPTNO, JOB ORDER BY DEPTNO ASC, JOB ASC;
--평균 급여 2000 이상 => 전체 사원 14명을 가지고 그룹화
SELECT DEPTNO, JOB, AVG(SAL) FROM EMP 
    GROUP BY DEPTNO, JOB 
    HAVING AVG(SAL) >= 2000
    ORDER BY DEPTNO ASC, JOB ASC;
--직책이 CLERK 인 경우 출력
SELECT DEPTNO, JOB, AVG(SAL) FROM EMP 
    GROUP BY DEPTNO, JOB 
    HAVING JOB = 'CLERK'
    ORDER BY DEPTNO ASC, JOB ASC;
--WHERE 절과 비교  => 사원 6명을 가지고 그룹화
SELECT DEPTNO, JOB FROM EMP WHERE SAL >= 2000;
SELECT DEPTNO, JOB, AVG(SAL) FROM EMP WHERE SAL >= 2000
    GROUP BY DEPTNO, JOB 
    HAVING AVG(SAL) >= 2000
    ORDER BY DEPTNO ASC, JOB ASC;
--그룹화와 관련된 함수 = GROUP BY 와 함께 사용하는 함수
--먼저 GROUP BY 로 결과 출력
SELECT DEPTNO, JOB, COUNT(*), MAX(SAL), SUM(SAL), AVG(SAL) FROM EMP
    GROUP BY DEPTNO, JOB
    ORDER BY DEPTNO ASC, JOB ASC;
--ROLLUP: 열의 개수 + 1 개의 결과 출력
--1) A + B = 부서번호 + 직책 으로 GROUP BY
--2) A = 부서번호 로 GROUP BY
--3) 전체
SELECT DEPTNO, JOB, COUNT(*), MAX(SAL), SUM(SAL), AVG(SAL) FROM EMP
    GROUP BY ROLLUP(DEPTNO, JOB);
--CUBE: 2의 열의 개수 제곱 개의 결과 출력
--1) A + B = 부서번호 + 직책 으로 GROUP BY
--2) A = 부서번호 로 GROUP BY
--3) B = 직책 으로 GROUP BY
--4) 전체
SELECT DEPTNO, JOB, COUNT(*), MAX(SAL), SUM(SAL), AVG(SAL) FROM EMP
    GROUP BY CUBE(DEPTNO, JOB);
--ROLLUP 을 일부 열만 가지고 사용
--1) A + B = 부서번호 + 직책 으로 GROUP BY
--2) A = 부서번호 로 GROUP BY
--전체는 나오지 않음
SELECT DEPTNO, JOB, COUNT(*), MAX(SAL), SUM(SAL), AVG(SAL) FROM EMP
    GROUP BY DEPTNO, ROLLUP(JOB);
--1) A + B = 부서번호 + 직책 으로 GROUP BY
--2) A = 직책 으로 GROUP BY
--전체는 나오지 않음
SELECT DEPTNO, JOB, COUNT(*), MAX(SAL), SUM(SAL), AVG(SAL) FROM EMP
    GROUP BY JOB, ROLLUP(DEPTNO);
--GROUPING SETS
--1) A = 부서번호 로 GROUP BY
--2) B = 직책 으로 GROUP BY
SELECT DEPTNO, JOB, COUNT(*), MAX(SAL), SUM(SAL), AVG(SAL) FROM EMP
    GROUP BY GROUPING SETS(DEPTNO, JOB);
--GROUPING
--1) A + B = 부서번호 + 직책 으로 GROUP BY => 0 0
--2) A = 부서번호 로 GROUP BY => 0 1
--3) B = 직책 으로 GROUP BY => 1 0
--4) 전체 => 1 1
SELECT DEPTNO, JOB, COUNT(*), MAX(SAL), SUM(SAL), AVG(SAL), 
       GROUPING(DEPTNO), GROUPING(JOB) 
    FROM EMP
    GROUP BY CUBE(DEPTNO, JOB);
--GROUPING_ID
--1) A + B = 부서번호 + 직책 으로 GROUP BY => 0 0 => 0
--2) A = 부서번호 로 GROUP BY => 0 1 => 1
--3) B = 직책 으로 GROUP BY => 1 0 => 2
--4) 전체 => 1 1 => 3
SELECT DEPTNO, JOB, COUNT(*), MAX(SAL), SUM(SAL), AVG(SAL), 
       GROUPING(DEPTNO), GROUPING(JOB), GROUPING_ID(DEPTNO, JOB)
    FROM EMP
    GROUP BY CUBE(DEPTNO, JOB);
--DECODE 문으로 비어있는 값을 채워보자
--비어있는 값 = 그룹화에 사용되지 않음 = GROUPING 함수 결과 1
SELECT DECODE(GROUPING(DEPTNO), 1, 'ALL_DEPT', DEPTNO) AS DEPTNO, 
       DECODE(GROUPING(JOB), 1, 'ALL_JOB', JOB) AS JOB, 
       COUNT(*), MAX(SAL), SUM(SAL), AVG(SAL) FROM EMP
    GROUP BY CUBE(DEPTNO, JOB);
--LISTAGG
SELECT ENAME FROM EMP;
SELECT DEPTNO, ENAME FROM EMP GROUP BY DEPTNO, ENAME ORDER BY DEPTNO ASC, ENAME ASC;
--부서 별로 사원 이름을 알파벳 순서대로 나열한 다음 이름과 이름 사이에 ', ' 로 연결시켜 출력 
SELECT DEPTNO, 
       LISTAGG(ENAME, ', ') WITHIN GROUP(ORDER BY ENAME ASC) AS ENAME
       FROM EMP GROUP BY DEPTNO;
--부서 별로 사원 이름을 급여가 높은 순서대로 나열한 다음 이름과 이름 사이에 ', ' 로 연결시켜 출력 
SELECT DEPTNO, 
       LISTAGG(ENAME, ', ') WITHIN GROUP(ORDER BY SAL DESC) AS ENAME
       FROM EMP GROUP BY DEPTNO;
--PIVOT: 행을 열로 바꿈
SELECT DEPTNO, JOB, MAX(SAL) FROM EMP GROUP BY DEPTNO, JOB ORDER BY DEPTNO ASC, JOB ASC;
--부서번호를 행에서 열로 바꿈
SELECT * FROM (SELECT DEPTNO, JOB, SAL FROM EMP)
    PIVOT(MAX(SAL) FOR DEPTNO IN (10, 20, 30))
    ORDER BY JOB;
--직책을 행에서 열로 바꿈
SELECT * FROM (SELECT DEPTNO, JOB, SAL FROM EMP)
    PIVOT(MAX(SAL) FOR JOB IN ('ANALYST' AS ANALYST, 
                               'CLERK' AS CLERK, 
                               'MANAGER' AS MANAGER, 
                               'PRESIDENT' AS PRESIDENT, 
                               'SALESMAN' AS SALESMAN))
    ORDER BY DEPTNO;
--DECODE 문으로 PIVOT 테이블 만들어 보자
--직책을 행에서 열로 바꿈
SELECT DEPTNO, 
       MAX(DECODE(JOB, 'ANALYST', SAL)) AS ANALYST, 
       MAX(DECODE(JOB, 'CLERK', SAL)) AS CLERK, 
       MAX(DECODE(JOB, 'MANAGER', SAL)) AS MANAGER, 
       MAX(DECODE(JOB, 'PRESIDENT', SAL)) AS PRESIDENT, 
       MAX(DECODE(JOB, 'SALESMAN', SAL)) AS SALESMAN
    FROM EMP
    GROUP BY DEPTNO
    ORDER BY DEPTNO;
--UNPIVOT
--PIVOT 테이블을 다시 UNPIVOT
SELECT * FROM(SELECT DEPTNO, 
       MAX(DECODE(JOB, 'ANALYST', SAL)) AS ANALYST, 
       MAX(DECODE(JOB, 'CLERK', SAL)) AS CLERK, 
       MAX(DECODE(JOB, 'MANAGER', SAL)) AS MANAGER, 
       MAX(DECODE(JOB, 'PRESIDENT', SAL)) AS PRESIDENT, 
       MAX(DECODE(JOB, 'SALESMAN', SAL)) AS SALESMAN
    FROM EMP
    GROUP BY DEPTNO
    ORDER BY DEPTNO)
    UNPIVOT (SAL FOR JOB IN (ANALYST, CLERK, MANAGER, PRESIDENT, SALESMAN))
    ORDER BY DEPTNO, JOB;
--

 

'Daily > 디지털하나로' 카테고리의 다른 글

시각화 도구 seaborn  (0) 2023.06.15
데이터 분석 관련 필수 라이브러리 : pandas, matplotlib  (0) 2023.06.15
SQL 이론&실습 (2)  (0) 2023.06.13
데이터 분석 기초 이론  (1) 2023.06.08
파이썬 기초 실습  (1) 2023.06.07

댓글