- SELECT문의 실행 결과(RESULT SET)를 저장하는 객체
- 논리적 가상 테이블
-> 테이블 모양을 하고는 있지만, 실제 값을 저장하고 있지는 않음
1) 복잡한 SELECT문을 쉽게 재사용하기 위해서 사용함
2) 테이블의 진짜 모습을 감출 수 있어 보안 상 유리함
1) 가상의 테이블(실체 X)이기 때문에 ALTER 구문 사용 불가능
2) VIEW를 이용한 DML(INSERT, UPDATE, DELETE)가 가능한 경우도 있지만 제약이 많이 따르기 때문에 보통은 조회(SELECT) 용도로 많이 사용
CREATE [OR REPLACE] [FORCE | NOFORCE] VIEW 뷰이름 [(alias[,alias]...]
AS subquery
[WITH CHECK OPTION]
[WITH READ ONLY];
기존에 동일한 뷰 이름이 존재하는 경우 덮어쓰고, 존재하지 않으면 새로 생성
서브쿼리에 사용된 테이블이 존재하지 않아도 뷰 생성
서브쿼리에 사용된 테이블이 존재해야만 뷰 생성(기본값)
옵션을 설정한 컬럼의 값을 수정 불가능하게 함
뷰에 대해 조회만 가능(DML 수행 불가)
-- EMPLOYEE 테이블에서
-- 모든 사원의 사번, 이름, 부서명, 직급명 조회
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, JOB_NAME
FROM EMPLOYEE
LEFT JOIN DEPARTMENT ON(DEPT_CODE = DEPT_ID)
JOIN JOB USING(JOB_CODE);
--> 자주 사용하는데 매번 쓰기 힘들다...... -> VIEW 생성
-- 사번, 이름, 부서명, 직급명 VIEW 생성
CREATE VIEW VIEW_EMP
AS SELECT EMP_ID, EMP_NAME, DEPT_TITLE, JOB_NAME
FROM EMPLOYEE
LEFT JOIN DEPARTMENT ON(DEPT_CODE = DEPT_ID)
JOIN JOB USING(JOB_CODE);
-- ORA-01031: 권한이 불충분합니다
-- View VIEW_EMP이(가) 생성되었습니다.
--> 각자 이니셜 계정에 VIEW 생성 권한을 부여
-- (실행 시 관리자 계정으로 할 것)
GRANT CREATE VIEW TO ash;
--> 다시 이니셜 계정으로 접속 -> 뷰 생성 구문 다시 실행
-- VIEW를 이용한 조회
SELECT * FROM VIEW_EMP;
--------------------------------------------------------------------------------
-- ** OR REPLACE + 별칭 **
CREATE OR REPLACE VIEW VIEW_EMP
AS SELECT EMP_ID 사번, EMP_NAME 이름, DEPT_TITLE 부서명, JOB_NAME 직급명
FROM EMPLOYEE
LEFT JOIN DEPARTMENT ON(DEPT_CODE = DEPT_ID)
JOIN JOB USING(JOB_CODE);
-- ORA-00955: 기존의 객체가 이름을 사용하고 있습니다.
--> OR REPLACE 옵션 사용
-- 별칭이 적용된 VIEW에서 직급이 '대리'인 직원만 조회
--> VIEW에서 조회된 컬럼의 이름을 조건절에 사용해야 한다.
SELECT * FROM VIEW_EMP
WHERE 직급명 = '대리';
--------------------------------------------------------------------------------
-- * VIEW를 이용한 DML 확인 *
-- 테이블 복사
CREATE TABLE DEPT_COPY2
AS SELECT * FROM DEPARTMENT;
SELECT * FROM DEPT_COPY2;
-- 복사한 테이블을 이용해서 VIEW 생성
CREATE OR REPLACE VIEW V_DCOPY2
AS SELECT DEPT_ID, LOCATION_ID FROM DEPT_COPY2;
-- 뷰 생성 확인
SELECT * FROM V_DCOPY2;
-- 뷰를 이용한 INSERT
INSERT INTO V_DCOPY2 VALUES('D0', 'L3'); -- 1 행 이(가) 삽입되었습니다.
-- 삽입 확인
SELECT * FROM V_DCOPY2; --> VIEW에 'D0'가 삽입된 것을 확인함
--> 가상의 테이블인 VIEW에 데이터 삽입이 가능한 걸까? NO
-- 원본 테이블 확인
SELECT * FROM DEPT_COPY2; -- 'D0', NULL, 'L3'
--> VIEW에 삽입한 내용이 원본 테이블에 존재함
--> VIEW를 이용한 DML 구문이 원본에 영향을 미친다.
-- VIEW를 이용한 DML 사용 시 발생하는 문제점 == 제약조건 위배 현상
ROLLBACK;
SELECT * FROM DEPT_COPY2;
SELECT * FROM V_DCOPY2;
-- 원본 테이블 DEPT_TITLE 컬럼에 NOT NULL 제약조건 추가
ALTER TABLE DEPT_COPY2
MODIFY DEPT_TITLE NOT NULL;
-- 현 상태에서 다시 VIEW를 이용한 INSERT 수행
INSERT INTO V_DCOPY2 VALUES('D0', 'L3');
-- ORA-01400: NULL을 ("ASH"."DEPT_COPY2"."DEPT_TITLE") 안에 삽입할 수 없습니다
--> VIEW를 이용한 INSERT 시 원본 테이블에 삽입이 된다.
--> 원본 테이블 삽입 시 VIEW INSERT 구문이 미포함된 컬럼에는 NULL이 저장된다.
--> 그런데 DEPT_TITLE 컬럼에 NOT NULL 제약 조건이 설정되어 있음
--> 오류 발생! > VIEW를 이용한 INSERT 실패
-- 결론 : VIEW 가지고 DML 웬만하면 하지 마세요..
--------------------------------------------------------------------------------
-- * WITH READ ONLY 옵션 *
CREATE OR REPLACE VIEW V_DCOPY2
AS SELECT DEPT_ID, LOCATION_ID FROM DEPT_COPY2
WITH READ ONLY; -- 읽기 전용의 VIEW 생성(DML X)
INSERT INTO V_DCOPY2 VALUES('D0', 'L1');
-- ORA-42399: 읽기 전용 뷰에서는 DML 작업을 수행할 수 없습니다.
순차적 번호 자동 발생기 역할의 객체
EX) 1 2 3 4 5 6 7 8 9 ...
CREATE SEQUENCE 시퀀스이름
[START WITH 숫자] -- 처음 발생시킬 시작값 지정, 생략하면 자동 1이 기본
[INCREMENT BY 숫자] -- 다음 값에 대한 증가치, 생략하면 자동 1이 기본
[MAXVALUE 숫자 | NOMAXVALUE] -- 발생시킬 최대값 지정 (10의 27승 -1)
[MINVALUE 숫자 | NOMINVALUE] -- 최소값 지정 (-10의 26승)
[CYCLE | NOCYCLE] -- 값 순환 여부 지정
[CACHE 바이트크기 | NOCACHE] -- 캐쉬메모리 기본값은 20바이트, 최소값은 2바이트
다음 시퀀스 번호를 얻어옴 (INCREMENT BY만큼 증가된 값)
단, 시퀀스 생성 후 첫 호출인 경우 START WITH의 값을 얻어옴
현재 시퀀스 번호를 얻어옴
단, 시퀀스 생성 후 NEXTVAL 호출 없이 CURRVAL를 호출하면 오류 발생
SELECT * FROM EMPLOYEE_COPY4;
-- EMPLOYEE_COPY4 테이블의 EMP_NAME 컬럼에 INDEX 생성
CREATE INDEX ECOPY4_NAME_IDX
ON EMPLOYEE_COPY4(EMP_NAME);
-- Index ECOPY4_NAME_IDX이(가) 생성되었습니다.
SELECT * FROM EMPLOYEE_COPY4;
--> 인덱스를 사용하지 않은 검색
-- *** 인덱스를 이용한 조회(검색) 방법 ***
--> WHERE절에 인덱스가 추가된 컬럼이 언급되면 자동으로 INDEX가 활용됨
SELECT * FROM EMPLOYEE_COPY4
WHERE EMP_NAME != '0';
--> 데이터가 너무 적어서 차이가 거의 없음...
-- 인덱스 확인용 테이블 생성
CREATE TABLE TB_IDX_TEST(
TEST_NO NUMBER PRIMARY KEY, -- 자동으로 인덱스가 생성됨
TEST_ID VARCHAR2(20) NOT NULL
);
-- TB_IDX_TEST 테이블에 샘플데이터 100만개 삽입 (PL/SQL 사용)
BEGIN
FOR I IN 1..1000000
LOOP
INSERT INTO TB_IDX_TEST VALUES( I , 'TEST' || I );
END LOOP;
COMMIT;
END;
/
SELECT COUNT(*) FROM TB_IDX_TEST;
-- 인덱스 사용 X
SELECT * FROM TB_IDX_TEST
WHERE TEST_ID = 'TEST500000'; -- 0.019초
-- 인덱스 사용 O
SELECT * FROM TB_IDX_TEST
WHERE TEST_NO = 500000; -- 0.002초
-- 테스트용 테이블 삭제
DROP TABLE TB_IDX_TEST;
-- 인덱스 삭제
DROP INDEX ECOPY4_NAME_IDX;