뷰
* SELECT(조회용 쿼리문)을 저장해둘 수 있는 표 형태의 객체
* 자주 쓰일법한 긴 SELECT문을 저장해두면 매번 긴 SELECT문을 작성할 필요가 없어짐.
* 임시테이블 같은 존재(실제 데이터가 담겨있는 것은 아님.
SELECT * FROM EMPLOYEE;
SELECT * FROM DEPARTMENT;
SELECT * FROM JOB;
SELECT * FROM LOCATION;
SELECT * FROM NATIONAL;
SELECT DISTINCT DEPT_CODE FROM EMPLOYEE ORDER BY DEPT_CODE ASC;
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY, NATIONAL_NAME, JOB_NAME
FROM EMPLOYEE E, DEPARTMENT D, JOB J, LOCATION L, NATIONAL N
WHERE E.DEPT_CODE = D.DEPT_ID(+)
AND E.JOB_CODE = J.JOB_CODE
AND D.LOCATION_ID = L.LOCAL_CODE(+)
AND L.NATIONAL_CODE = N.NATIONAL_CODE(+)
AND N.NATIONAL_NAME = '한국';
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY, NATIONAL_NAME, JOB_NAME
FROM EMPLOYEE E
LEFT JOIN DEPARTMENT D ON(E.DEPT_CODE = D.DEPT_ID)
LEFT JOIN LOCATION L ON(D.LOCATION_ID = L.LOCAL_CODE)
LEFT JOIN NATIONAL N USING(NATIONAL_CODE)
JOIN JOB J USING(JOB_CODE)
WHERE N.NATIONAL_NAME = '한국';
뷰 생성
* [표현법]
* CREATE VIEW 뷰명
* AS(서브쿼리);
*
* CREATE OR REPLACE VIEW 뷰
* AS(서브쿼리);
* => 뷰 생성시, 기존에 중복된 이름의 뷰가 없다면, 해당 뷰명의 VIEW를 생성(CREATE)
* => 뷰 생성시, 기존에 중복된 이름의 뷰가 있다면, 해당 VIEW를 변경하는 옵션(OR REPLACE)
DROP VIEW VW_EMPLOYEE;
CREATE VIEW VW_EMPLOYEE
AS (SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY, NATIONAL_NAME, JOB_NAME
FROM EMPLOYEE E
LEFT JOIN DEPARTMENT D ON(E.DEPT_CODE = D.DEPT_ID)
LEFT JOIN LOCATION L ON(D.LOCATION_ID = L.LOCAL_CODE)
LEFT JOIN NATIONAL N USING(NATIONAL_CODE)
JOIN JOB J USING(JOB_CODE));
SELECT *
FROM(SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY, NATIONAL_NAME, JOB_NAME
FROM EMPLOYEE E
LEFT JOIN DEPARTMENT D ON(E.DEPT_CODE = D.DEPT_ID)
LEFT JOIN LOCATION L ON(D.LOCATION_ID = L.LOCAL_CODE)
LEFT JOIN NATIONAL N USING(NATIONAL_CODE)
JOIN JOB J USING(JOB_CODE));
GRANT CREATE VIEW TO KH;
SELECT * FROM VW_EMPLOYEE;
SELECT *
FROM VW_EMPLOYEE
WHERE NATIONAL_NAME = '한국';
SELECT *
FROM VW_EMPLOYEE
WHERE NATIONAL_NAME = '러시아';
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY, NATIONAL_NAME, JOB_NAME, BONUS
FROM VW_EMPLOYEE
WHERE NATIONAL_NAME = '러시아';
CREATE OR REPLACE VIEW VW_EMPLOYEE
AS (SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY, NATIONAL_NAME, JOB_NAME, BONUS
FROM EMPLOYEE E, DEPARTMENT D, JOB J, LOCATION L, NATIONAL N
WHERE E.DEPT_CODE = D.DEPT_ID(+)
AND E.JOB_CODE = J.JOB_CODE
AND D.LOCATION_ID = L.LOCAL_CODE(+)
AND L.NATIONAL_CODE = N.NATIONAL_CODE(+));
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY, NATIONAL_NAME, JOB_NAME, BONUS
FROM VW_EMPLOYEE
WHERE NATIONAL_NAME = '러시아';
SELECT * FROM USER_VIEWS;
뷰 컬럼에 별칭 부여
* 서브쿼리의 SELECT절에 함수나 산술연산식이 사용될 경우, 반드시 별칭을 부여해주어야 함.
CREATE OR REPLACE VIEW VW_EMP_JOB
AS (SELECT EMP_ID, EMP_NAME, JOB_NAME,
DECODE(SUBSTR(EMP_NO,8,1),'1','남','2','여'),
EXTRACT(YEAR FROM SYSDATE)- EXTRACT(YEAR FROM HIRE_DATE)
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE));
CREATE OR REPLACE VIEW VW_EMP_JOB
AS (SELECT EMP_ID, EMP_NAME, JOB_NAME,
DECODE(SUBSTR(EMP_NO,8,1),'1','남','2','여')"성별",
EXTRACT(YEAR FROM SYSDATE)- EXTRACT(YEAR FROM HIRE_DATE)"근무년수"
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE));
SELECT * FROM VW_EMP_JOB;
CREATE OR REPLACE VIEW VW_EMP_JOB (사번,이름,직급명,성별,근속년수)
AS (SELECT EMP_ID, EMP_NAME, JOB_NAME,
DECODE(SUBSTR(EMP_NO,8,1),'1','남','2','여'),
EXTRACT(YEAR FROM SYSDATE)- EXTRACT(YEAR FROM HIRE_DATE)
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE));
SELECT * FROM VW_EMP_JOB;
SELECT 사번, 근속년수
FROM VW_EMP_JOB;
SELECT 사번, 이름, 직급명
FROM VW_EMP_JOB
WHERE 성별 = '남';
SELECT *
FROM VW_EMP_JOB
WHERE 근속년수 >=20;
DROP VIEW VW_EMP_JOB;
뷰에서 DML사용하기
* 단, 뷰를 통해서 DML(insert,update,delete)을 사용하면,
* 실제 데이터가 담겨있는 원본테이블의 데이터도 바뀜.
CREATE OR REPLACE VIEW VW_JOB
AS(SELECT * FROM JOB);
SELECT * FROM VW_JOB;
SELECT * FROM JOB;
INSERT INTO VW_JOB
VALUES('J8','인턴');
UPDATE VW_JOB
SET JOB_NAME = '알바'
WHERE JOB_CODE = 'J8' ;
DELETE FROM VW_JOB
WHERE JOB_CODE = 'J8';
뷰의 DML사용이 불가능한 경우
* 뷰를 가지고 DML이 불가능한 경우가 더 많음.
* 1) 뷰에 정의되어있지 않은 컬럼을 조작하는 경우
* 2) 뷰에 정의되어있지 않은 컬럼 중에, 원본테이블상에 NOT NULL제약조건이 지정된 경우
* 3) 산술연산식 또는 함수를 통해서 정의되어 있는 경우
* 4) 그룹함수나 GROUP BY절이 포함되어있는 경우
* 5) DISTINCT 구문이 있을 경우
* 6) JOIN을 이용해서 여러 테이블을 매칭시켜놓은 경우
* => 대부분 원본테이블과 관련하여 생각해보면 됨.
CREATE OR REPLACE VIEW VW_JOB
AS(SELECT JOB_CODE FROM JOB);
SELECT * FROM VW_JOB;
INSERT INTO VW_JOB(JOB_CODE, JOB_NAME)
VALUES('J8','인턴');
UPDATE VW_JOB
SET JOB_NAME = '인턴'
WHERE JOB_CODE = 'J7';
DELETE FROM VW_JOB
WHERE JOB_NAME = '사원';
CREATE OR REPLACE VIEW VW_JOB
AS(SELECT JOB_NAME FROM JOB);
SELECT * FROM JOB;
SELECT * FROM VW_JOB;
INSERT INTO VW_JOB VALUES('인턴');
UPDATE VW_JOB
SET JOB_NAME = '알바'
WHERE JOB_NAME = '사원';
UPDATE VW_JOB
SET JOB_CODE = NULL
WHERE JOB_NAME = '알바';
DELETE FROM VW_JOB
WHERE JOB_NAME = '대리';
DELETE FROM VW_JOB
WHERE JOB_NAME = '알바';
CREATE OR REPLACE VIEW VW_EMP_SAL
AS (SELECT EMP_ID, EMP_NAME, SALARY, SALARY*12 "연봉"
FROM EMPLOYEE);
SELECT * FROM VW_EMP_SAL;
SELECT * FROM EMPLOYEE;
INSERT INTO VW_EMP_SAL
VALUES(400,'정진훈', 3000000, 36000000);
UPDATE VW_EMP_SAL
SET "연봉" = 80000000
WHERE EMP_ID = 200;
UPDATE VW_EMP_SAL
SET SALARY = 7000000
WHERE EMP_ID = 200;
DELETE FROM VW_EMP_SAL
WHERE 연봉 = 72000000;
ROLLBACK;
CREATE OR REPLACE VIEW VW_GROUPDEPT
AS(SELECT DEPT_CODE, SUM(SALARY) "급여합", FLOOR(AVG(SALARY)) "평균급여"
FROM EMPLOYEE
GROUP BY DEPT_CODE);
SELECT * FROM VW_GROUPDEPT;
INSERT INTO VW_GROUPDEPT
VALUES('D0', 80000000, 40000000);
UPDATE VW_GROUPDEPT
SET 급여합 = 8000000
WHERE DEPT_CODE = 'D1';
UPDATE VW_GROUPDEPT
SET DEPT_CODE = 'D0'
WHERE DEPT_CODE = 'D1';
DELETE FROM VW_GROUPDEPT
WHERE DEPT_CODE = 'D1';
CREATE OR REPLACE VIEW VW_DT_JOB
AS(SELECT DISTINCT JOB_CODE
FROM EMPLOYEE);
SELECT * FROM VW_DT_JOB;
INSERT INTO VW_DT_JOB VALUES('J8');
UPDATE VW_DT_JOB
SET JOB_CODE = 'J8'
WHERE JOB_CODE = 'J7';
DELETE FROM VW_DT_JOB
WHERE JOB_CODE = 'J7';
CREATE OR REPLACE VIEW VW_JOINEMP
AS (SELECT EMP_ID, EMP_NAME, DEPT_TITLE
FROM EMPLOYEE
JOIN DEPARTMENT ON(DEPT_CODE= DEPT_ID));
SELECT * FROM VW_JOINEMP;
INSERT INTO VW_JOINEMP VALUES(888,'조세오','총무부');
UPDATE VW_JOINEMP
SET EMP_NAME = '서동일'
WHERE EMP_ID = 200;
SELECT * FROM EMPLOYEE;
DELETE FROM VW_JOINEMP
WHERE EMP_ID = 200;
SELECT * FROM VW_JOINEMP;
SELECT * FROM EMPLOYEE;
SELECT * FROM DEPARTMENT;
DELETE FROM VW_JOINEMP
WHERE DEPT_TITLE = '총무부';
SELECT * FROM VW_JOINEMP;
SELECT * FROM VW_JOINEMP;
ROLLBACK;
뷰 옵션
* [상세표현법]
* CREATE OR REPLACE [FORCE / NOFORCE] 뷰명
* AS (서브쿼리)
* WITH CHECK OPTION
* WITH READ ONLY
*
* 1) FORCE / NOFORCE
* - FORCE : 서브쿼리에 기술된 테이블이 존재하지 않더라도 뷰를 생성
* - NOFORCE : 서브쿼리에 기술된 테이블이 반드시 존재해야만 뷰를 생성
* 생략시 기본값임.
* 2) WITH CHECK OPTION : 서브쿼리의 조건절에 기술된 내용에 만족하는 값으로만 DML이 가능
* 조건에 부합하지 않는 값으로 수정하는 경우 오류 발생
* 3) WITH READ ONLY : 뷰에 대해 조회만 가능.
CREATE OR REPLACE VIEW VW_TEST
AS(SELECT TCODE, TNAME, TCONTENT
FROM TT);
CREATE OR REPLACE FORCE VIEW VW_TEST
AS(SELECT TCODE, TNAME, TCONTENT
FROM TT);
SELECT * FROM VW_TEST;
CREATE TABLE TT(
TCODE NUMBER,
TNAME VARCHAR2(30),
TCONTENT VARCHAR2(50)
);
SELECT * FROM VW_TEST;
CREATE OR REPLACE VIEW VW_EMP
AS
(SELECT *
FROM EMPLOYEE
WHERE SALARY >= 3000000)
WITH CHECK OPTION;
SELECT * FROM VW_EMP;
UPDATE VW_EMP
SET SALARY = 2000000
WHERE EMP_ID = 200;
UPDATE VW_EMP
SET SALARY = 4000000
WHERE EMP_ID = 200;
SELECT * FROM VW_EMP;
ROLLBACK;
CREATE OR REPLACE VIEW VW_EMPBONUS
AS(SELECT EMP_ID, EMP_NAME, BONUS
FROM EMPLOYEE
WHERE BONUS IS NOT NULL)
WITH READ ONLY;
SELECT * FROM VW_EMPBONUS;
DELETE FROM VW_EMPBONUS
WHERE EMP_ID = 204;