[2과목] SQL 활용
😸 표준 조인
- ANSI/ISO 표준 SQL에서 규정한 조인 기법
- 내부 조인(Inner Join), 외부 조인(Outer Join), 크로스 조인(Cross Join), 자연 조인(Natural Join)이나 표준 조인 조건절인
ON, USING을 통해 테이블 간 JOIN 조건을 FROM 절에서 명시적 정의
- NATURAL JOIN
- 두 테이블 간에 동일한 이름, 타입을 가진 컬럼을 조인
- 조인에 이용하는 컬럼은 명시하지 않아도 자동으로 조인
- 동일한 이름이나 데이터 타입이 다르면 에러 발생
ex) SELECT STU_NO, STU_NAME FROM STUDENT NATURAL JOIN ENROL WHERE SUB_NO IN(101, 102);
-> 과목번호가 101 또는 102를 수강하는 학생의 학번과 이름을 출력
- USING JOIN
- 조인에 사용될 컬럼을 지정하고, 조인 컬럼은 괄호로 묶어서 기술
- NATURAL절과 USING절은 함께 사용할 수 없음
ex) SELECT STU_NO, STU_NAME FROM STUDENT JOIN ENROL USING(STU_NO) WHERE SUB_NO IN(101,102);
-> 과목번호가 101 또는 102를 수강하는 학생의 학번과 이름을 출력
- CROSS JOIN
- 공통 분모가 없이 서로 합쳐지는 조인 (TABLE 통합)
ex) SELECT STUDENT.STU_NO, ENROL.SUB_NO FROM STUDENT CROSS JOIN ENROL;
# Inner Join
SELECT 컬럼명 FROM 테이블1 INNER JOIN 테이블2 ON 조건절;
# Outer Join
SELECT 컬럼명 FROM 테이블 (LEFT, RIGHT) OUTER JOIN 테이블2 ON 조건절;
# Full Outer Join
SELECT 컬럼명 FROM 테이블 FULL OUTER JOIN 테이블2 ON 조건절;
# Cross Join
SELECT 컬럼명 FROM 테이블1 CROSS JOIN 테이블2;
# Natural Join
SELECT 컬럼명 FROM 테이블1 NATURAL JOIN 테이블2;
# ON 조건절
SELECT 컬럼명 FROM 테이블1 JOIN 테이블2 ON 조건절;
# USING 조건절
SELECT 컬럼명 FROM 테이블1 JOIN 테이블2 USING 조건절;
👉 관계 대수
- 집합 연산자
자동 정렬 | 속 도 | 특 징 | |
UNION (합집합) | O | 느림 | 중복 제거 O |
UNION ALL (합집합) | X | 빠름 | 중복 제거 X |
INTERSECT (교집합) | O | 느림 | 교집합 |
MINUS or EXCEPT (차집합) | O | 느림 | 차집합 |
👉 계층형 질의
- 계층형 질의 문법
SELECT 컬럼명 FROM 테이블명 WHERE 조건 START WITH 조건
CONNECT BY [NOCYCLE] 조건 [ORDER SLBLINGS BY 컬럼명];
- 순방향 계층형 질의
ex) SELECT EMP_ID, EMP_NAME, MGR_ID, LEVEL, CONNECT BY_ISLEAF AS ISLEAF,
SYS_CONNECT_BY_PATH(EMP_NAME, '/') AS EMP_PATH, CONNECT_BY_ROOT(EMP_NAME) AS ROOT
FROM EMP START WITH MGR_ID IS NULL
CONNECT BY PRIOR EMP_ID = MGR_ID;
- 역방향 계층형 질의
ex) SELECT EMP_ID, EMP_NAME, MGR_ID, LEVEL, CONNECT BY_ISEAF AS ISLEAF,
SYS_CONNECT_BY_PATH(EMP_NAME, '/') AS EMP_PATH, CONNECT_BY_ROOT(EMP_NAME) AS ROOT
FROM EMP START WITH EMP_ID = '105'
CONNECT BY EMP_ID = PRIOR MGR_ID;
- 셀프 조인
: 한 테이블 내에서 두 컬럼 이상 내부적인 연관관계가 있을 경우 이용
ex) SELECT A.EMP_ID, A.EMP_NAME, A.MGR_ID, B.EMP_NAME AS MGR_NAME
FROM EMP A, EMP B WHERE A.MGR_ID = B.EMP_ID;
👉 서브쿼리
- SELECT : 스칼라서브쿼리
- FROM : 인라인뷰(메인쿼리의 컬럼 사용 가능)
- WHERE : 중첩 서브 쿼리
- GROUP BY : 사용불가
- HAVING : 중첩 서브 쿼리
- ORDER BY : 스칼라서브쿼리
- IN : 서브쿼리출력값들 or 조건
- ANY/ SOME : 서브쿼리출력값들 중 가장 작거나 큰 값과 비교
- EXISTS : 서브쿼리 내 SELECT절엔 뭐가 와도 상관없음. ROW가 있으면 TRUE, 없으면 FALSE
- 단일행 서브 쿼리
ex) SELECT EMP_ID, EMP_NAME, DEPT_ID FROM EMP
WHERE DEPT_ID = (SELECT DEPT_ID FROM EMP WHERE EMP_NAME = '홍길동');
- 다중행 서브 쿼리
ex) SELECT EMP_ID, EMP_NAME, DEPT_ID FROM EMP
WHERE EMP_ID IN (SELECT MGR_ID FROM DEPT);
- ALL 연산자
ex) SELECT EMP_ID, EMP_NAME, SALARY, JOB_TITLE FROM EMP
WHERE SALARY > ALL (SELECT SALARY FROM EMP WHERE JOB_TITLE = '과장');
- ANY 연산자
ex) SELECT EMP_ID, EMP_NAME, SALARY, JOB_TITLE FROM EMP
WHERE SALARY > ANY (SELECT SALARY FROM EMP WHERE JOB_TITLE =' 과장');
- EXISTS 연산자
ex) SELECT A.EMP_ID, A.EMP_NAME, A.SALARY FROM A
WHERE EXISTS (SELECT 1 FROM B WHERE A.SALARY = B.SALARY AND B.EMP_NAME = "홍길동");
- 다중 컬럼 서브 쿼리
ex) SELECT EMP_ID, EMP_NAME, DEPT_ID, MGR_ID FROM EMP
WHERE (DEPT_ID, MGR_ID) IN (SELECT DEPT_ID, MGR_ID FROM EMP WHERE EMP_NAME = "홍길동");
- 연관 서브 쿼리
ex) SELECT EMP_ID, EMP_NAME, DEPT_ID, SALARY FROM EMP A
WHERE SALARY > (SELECT AVG(SALARY) FROM EMP B WHERE A.DEPT_ID = B.DEPT_ID);
- 스칼라 서브 쿼리
ex) SELECT A.EMP_NAME, A.SALARY, (SELECT AVG(SALARY) FROM EMP WHERE DEPT_ID = A.DEPT_ID)
AS AVG_SALARY FROM EMP A;
- 인라인 뷰
: 동적뷰라고 한다
ex) SELECT B.DEPT_NAME, A.AVG_SALARY FROM (SELECT DEPT_ID, AVG(SALARY) AS AVG_SALARY
FROM EMP GROUP BY DEPT_ID) A, DEPT B WHERE A.DEPT_ID = B.DEPT_ID;
- 뷰 생성
ex) CREATE VIEW VW_EMP AS SELECT B.DEPT_NAME, A.EMP_NAME, A SALARY FROM EMP A, DEPT B
WHERE A.DEPT_ID = B.DEPT_ID;
- 뷰 조회
ex) SELECT DEPT_NAME, EMP_NAME, SALARY FROM VW_EMP;
👉 그룹 함수
- 전체 행을 하나 이상의 컬럼을 기준으로 컬럼값에 따라 그룹화하여 그룹별로 결과를 출력하는 함수
1) ROLLUP 함수
- 지정된 컬럼의 소계 및 총계를 구하기 위해 사용하는 그룹 함수
- 지정 컬럼 수보다 하나 더 큰 레벨만큼의 중간 집계 값이 생성
SELECT 컬럼명, 집계함수 FROM 테이블명 [WHERE...]
GROUP BY [컬럼명] ROLLUP (그룹화할 컬럼) [HAVING...] [ORDER BY...];
ex) SELECT GENDER, AGE, SUM(PAY_AMOUNT) AS PAY_AMOUNT FROM PAY
GROUP BY ROLLUP (GENDER, AGE);
2) CUBE 함수
- 결합 가능한 모든 값에 대해 다차원 집계를 생성하는 그룹 함수
- 내부적으로 대상 컬럼의 순서를 변경하여 또 한번의 쿼리를 수행
- 다른 그룹 함수보다 성능상 불리함
- 기준 컬럼이 1개일 때 ROLLUP과 같음
SELECT 컬럼명, 집계함수 FROM 테이블명 [WHERE...]
GROUP BY [컬럼명] CUBE (그룹화할 컬럼) [HAVING...] [ORDER BY...];
ex) SELECT GENDER, AGE, SUM(PAY_AMOUNT) AS PAY_AMOUNT FROM PAY
GROUP BY CUBE (GENDER, AGE);
3) GROUPING SETS 함수
- 집계 대상 컬럼에 대한 소계를 구할 수 있는 그룹 함수
- ROLLUP과 달리 컬럼 간 순서와 무관한 결과를 얻을 수 있음
SELECT 컬럼명, 집계함수 FROM 테이블 [WHERE...]
GROUP BY [컬럼] GROUPING SETS (그룹화할 컬럼) [HAVING...] [ORDER BY...];
ex) SELECT GENDER, AGE, SUM(PAY_AMOUNT) AS PAY_AMOUNT FROM PAY
GROUP BY GROUPING SETS (GENDER, (GENDER, AGE)):
👉 계층형 SQL
- 한 테이블 안에 계층적인 데이터 구조를 가진 테이블에서 쉽게 데이터를 출력하기 위한 SQL 문법
# 순방향
SELECT 컬럼명 FROM 테이블 WHERE 조건절
START WITH 시작조건 CONNECT BY [NOCYCLE] PRIOR (부모->자식)
ORDER [SIBLINGS] BY 정렬조건
👉 윈도우 함수
- 데이터베이스에서 컬럼과 컬럼 간의 연산이 아닌 행과 행간의 비교 또는 연산 처리하는 함수
- 메인 쿼리 뿐아니라 서브 쿼리에서도 사용 가능하나, 함수 자체에서 중첩으로 사용할 수 없다
1) WINDOWING
ex) SELECT DEPT_NAME, EMP_NAME. SALARY, RANK() OVER(PARTITION BY DEPT_NAME ORDER BY SALARY DESC) AS "RANK", DENSE_RANK() OVER(PARTITION BY DEPT_NAME ORDER BY SALARY DESC) AS
"DENSE_RANK", ROW_NUMBER() OVER(PARTITION BY SALARY DESC) AS "ROW_NUMBER" FROM EMP;
2) 순위 함수
- 전체 또는 그룹 내에서 순위를 계산하는 함수로 ORDER BY를 필수로 사용
- RANK : 동일 값에 대해 동일 순위를 부여하고 중간 순위를 비워둔다. ex) 1 1 3 4 5
- DENSE_RANK: 동일 순위를 부여하되 중간 순위를 비우지 않는다. ex) 1 1 2 3 4
- ROW_NUMBER : 동일 값에 대해서도 유일한 순위를 부여한다. ex) 1 2 3 4 5
- RANK, DENSE_RANK, ROW_NUMBER
- 순위 추출을 위해서는 OVER절에 PARTITION BY 적용
3) 집계 함수
- 파티션 별 윈도우 합, 최댓값, 최솟값, 평균값, 건수를 계산하는 함수
- SUM, MAX, MIN, AVG, COUNT
4) 순서 함수
- 파티션별 윈도우에서 첫 번째 값, 마지막 값, 이전 행의 값, 이후 행의 값을 반환하는 함수
- FRIST_VALUE, LAST_VALUE, LAG, LEAD
5) 비율 함수
- 파티션 내 백분율을 계산하거나 비율에 따라 n 등분을 하는 함수
- RATIO_TO_REPORT, PERCENT_RANK, CUME_DIST, NTILE
👉 ROWNUM, ROWID, WITH문
- ROWNUM
- Oracle에서 출력 rows를 설정하는 기능
- Mysql에서 top() 기능으로 대체하여 사용 가능
SELECT *
FROM SALARY
WHERE ROWNUM < 3
SELECT TOP(2) *
FROM SALARY
- ROWID
- Oracle에서 row가 생성될 때 부여되는 row의 고유 id
- ROWID로 조건을 입력할 수 있음
- 데이터 객체번호, 상대적파일번호, 블록번호, 행번호의 조합
ex) SELECT ROWID, * FROM SALARY
- WITH
- 임시적인 VIEW 테이블로 특정 SQL 블록을 재사용하기 위해 사용
- SQL 실행 속도에 유리하게 작용하며 여러 번 사용될수록 유리
- 하나의 SQL문에서 여러 개의 WITH 사용 가능
WITH SQL1 AS (SELECT * FROM SALARY WHERE ROWNUM < 3),
SQL2 AS (SELECT * FROM SALARY WHERE ROWNUM < 2)
SELECT * FROM SQL1 UNION ALL
SELECT * FROM SQL2
-> SQL1에서 2줄, SQL2에서 1줄을 UNION ALL하여 총 3줄이 출력
- ROLE
- 권한과 유저 사이에 존재하는 개념으로 다양한 권한을 역할에 따라 유저에게 부여할 때 사용
- 특정 ROLE은 여러 권한을 받아 놓고 특정 유저에게 여러 권한을 가진 ROLE을 부여함으로 권한 관리 가능
ex) CREATE ROLE MY_ROLE GRANT CREATE SESSION, CREATE TABLE TO MY_ROLE
GRANT MY_ROLE TO MY_USER;
👉 Row Chaining vs Row migration
구분 | Row Chaining | Row Migration |
정의 | 하나의 Row를 하나의 블록에 저장할 수 없어서 여러 블록에 걸쳐서 저장하는 현상 |
UPDATE로 인하여 늘어나는 공간을 저장할 공간이 없어서 다른 블록으로 Row를 옮기는 현상 |
특성 | Initial Row Piece(행 조작)와 Row Pointer로 블록 내에 저장됨 |
기존 블록에는 Migration되는 데이터의 row reader와 블록 주소값을 갖게 되고, 새로운 블록에는 Migration되는 데이터가 저장됨 |
문제점 | Row의 정보를 검색하기 위해 하나 이상의 데이터 블록을 Scan 해야 하기 때문에 성능이 감소 | Migration된 Row를 읽기 전에 기존 블록에서 헤더를 통해 Migration된 Row를 읽기 때문에 성능이 감소 |
해결책 | 블록의 크기를 크게 만든다 | - PCTFREE를 크게 설정 - 객체를 Export하고 삭제한 후 import - 객체를 Migration 하고 Truncate |
👉 절차형 SQL
- PL / SQL의 특징
- Block 구조로 각 기능별로 모듈화 가능
- 변수, 상수 등을 선언하여 SQL 문장 간 값을 교환
- IF, LOOP등의 절차형 언어를 사용하여 절차적인 프로그램이 가능하도록 함
- DBMS 정의 에러나 사용자 정의 에러를 정의하여 사용 가능
- Oracle에 내장되어 있어 Oracle과 PL/SQL을 지원하는 어떤 서버로도 프로그램을 옮길 수 있음
- PL/SQL은 응용 프로그램의 성능을 향상 시킴
- PL/SQL은 여러 SQL 문장을 Block으로 묶고 한번에 서버로 보낼 수 있어 통신량 줄일 수 있음
1) Procedure
- 필요한 로직을 처리하기만 하고 결과값을 반환하지 않는 프로그램
- 테이블에서 데이터를 조회하고 변경하는 일련의 작업을 처리할 때 프로시저를 사용
ex) CREATE PROCEDURE DELETE_EMP(V_EMP_ID NUMBER) IS BEGIN
DELETE FROM EMP WHERE EMP_ID = V_EMP_ID; END;
2) Function
- 매개변수를 통해 입력받은 값을 처리하고 결과값을 반환하는 프로그램
- DBMS에서 제공하는 내장함수 외에도 사용자가 직접 작성 가능
- 저장형 함수는 단독적으로 실행되기 보다 다른 SQL문을 통해서 호출되고 그 결과를 반환하는 SQL의 보조적 역할
ex) CREATE FUNCTION GET_SALARY (V_EMP_ID NUMBER) RETURN NUMBER IS V_SALARY NUMBER(12);
BEGIN SELECT SALARY INTO V_SALARY FROM EMP WHERE EMP_ID = V_EMP_ID;
RETURN V_SALSARY; END;
3) Trigger
- 데이터의 무결성과 일관성을 위해 사용자 정의 함수인 트리거를 사용
- 데이터 입력, 수정, 삭제 등의 INSERT, UPDATE, DELETE문이 수행될 때 자동으로 실행되는 프로그램
- 주로 데이터 무결성 유지 및 로그 메시지 출력을 위해 사용
- 트리거 내 COMMIT, ROLLBACK 등 트랜잭션 제어어 사용 시 컴파일 에러 발생
- 트리거에서 에러 발생 시 트리거 이후 작업은 반영되지 않음
- 트리거는 데이터베이스 로그인 작업에서도 정의 가능
ex) CREATE TRIGGER T_EMP BERORE INSERT ON EMP FOR EACH ROW
BEGIN IF (:NEW.DEPT_ID IS NULL) THEN RAISE_APPLICATION_ERROR (-20502, '부서코드 입력 필수;): END IF; END;
PROCEDURE | TRIGGER |
EXECUTE 명령어로 실행 | 자동 실행 (이벤트 발생 시) |
CREATE PROCEDURE | CREATE TRIGGER |
COMMIT, ROLLBACK 가능 | COMMIT, ROLLBACK 불가능 |
👉 실행 계획
- OPERATION
SELECT STATEMENT
SORT GROUP BY
HASH JOIN OUTER
TABLE ACCESS BY INDEX ROWID
INDEX RANGE SCAN
TABLE ACCESS BY INDEX ROWID
INDEX SKOP SCAN