CREATE VIEW — 새 뷰 정의
CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] [ RECURSIVE ] VIEW이름
[ (칼럼이름
[, ...] ) ] [ WITH (뷰옵션이름
[=뷰옵션값
] [, ... ] ) ] AS쿼리
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
CREATE VIEW
명령은 지정한 쿼리를 바탕으로 새 뷰를 만든다. 뷰는 물리적으로 구체화하는 개체는 아니다. 뷰를 호출하면 매번
그 뷰에 지정한 쿼리를 실행한다.
CREATE OR REPLACE VIEW
명령은 이미 해당 뷰가 있다면,
그 뷰에서 사용할 쿼리를 바꾼다. 여기서 지정하는 쿼리의 출력 칼럼 정보는
정확히 일치해야 한다. (칼럼 이름, 순서, 자료형 모두 같아야 한다.)
단, 마지막에 새롭게 칼럼이 추가 되는 형태의 쿼리는 사용할 수 있다.
출력 칼럼 처리 계산은 완전히 다를 수 있다.(?)
뷰 이름 앞에 스키마 이름을 사용하면(예, CREATE VIEW
myschema.myview ...
), 그 뷰는 해당 스키마 안에 만들어진다.
스키마 이름을 지정하지 않으면 현재 스키마 안에 만들어진다. 임시 뷰는
특별한 스키마를 사용하기 때문에, 임시 뷰를 만들 때는 스키마 이름을
지정하지 않는다. 뷰 이름은 해당 스키마 안에서, 다른 뷰, 테이블,
시퀀스, 인덱스, 외부 테이블 이름들 가운데 유일해야 한다.
TEMPORARY
또는 TEMP
이 옵션을 사용하면, 임시 뷰를 만든다. 임시 뷰는 현재 세션이 종료 되면 자동 삭제 된다. 임시 뷰로 만드는 이름과 같은 일반 릴레이션이 있다면, 임시 뷰가 만들어지면, 임시 뷰의 스키마 우선 순위로 스키마 이름을 지정하지 않으면 이 임시 뷰를 먼저 선택하게 된다. 이럴 때는 스키마 이름까지 명확하게 지정해야한다.
만드는 뷰가 참조 하는 개체가 임시 뷰이거나 임시 테이블이라면,
암묵적으로 TEMPORARY
옵션을 사용해서
임시 뷰로 만들어진다.
RECURSIVE
재귀형 뷰를 만들 때 사용한다. 사용법은 다음과 같다:
CREATE RECURSIVE VIEW [스키마
. ]뷰이름
(칼럼이름
) AS SELECT...
;
같은 구문으로:
CREATE VIEW [스키마
. ]뷰이름
AS WITH RECURSIVE뷰이름
(칼럼이름
) AS (SELECT...
) SELECT칼럼이름
FROM뷰이름
;
재귀형 뷰를 위해서는 뷰 칼럼 이름 목록이 반드시 지정되어야 한다.
이름
만들 뷰 이름(스키마 이름 포함).
칼럼이름
뷰에서 사용하는 칼럼 이름 목록. 쿼리 결과로 만들어지는 칼럼 이름과 다르게 지정하고 싶을 때 사용한다.
WITH ( 뷰옵션이름
[= 뷰옵션값
] [, ... ] )
해당 뷰에 지정할 선택적 매개 변수와 그 값; 지원하는 옵션은 다음과 같다:
check_option
(enum
)
이 매개 변수 값으로 local
또는
cascaded
중 하나를 사용할 수 있으며,
WITH [ CASCADED | LOCAL ] CHECK OPTION
구문과 같은 역할을 한다. (아래에서 설명함)
이 옵션은 ALTER VIEW 명령으로 변경 할 수 있음.
security_barrier
(불리언
)로우 수준 보안 정책을 사용하는 경우 이 옵션을 사용한다. 40.5절에서 자세히 설명 한다.
쿼리
WITH [ CASCADED | LOCAL ] CHECK OPTION
이 옵션은 자동 DML이 가능한 뷰인 경우 그 동작 상태를 제어한다. 이
옵션을 사용하면, INSERT
, UPDATE
명령을 이 뷰 대상으로 실행하면, 뷰에 보이는 자료에 대해서만,
해당 작업을 한다. 이 옵션이 없으면, 이 뷰 정의와 관련되지 않아도
작업이 진행된다. (뷰는 어떤 정책에 의해 원치 않는 자료 전체나,
특정 칼럼을 보이지 않게 할 용도로 사용될 수 있다. 이런
제한 정책을 DML 작업에서 유지할 것인지, 안할 것인지를 지정하는 옵션이다.)
이 옵션은 두 가지 선태 사항을 지정할 수 있다:
LOCAL
이 작동 방식을 이 뷰만 대상으로 제한한 사항에 대해서만 자료 유효성을 검사한다. 이 뷰의 기반이 된 뷰에서 지정한 제한 사항은 무시한다.
CASCADED
이 작동 방식을 이 뷰와 이 뷰의 기반이 된 뷰에서 지정한
모든 제한 사항을 모두 검사한다.
특별히 그 기반이 된 뷰에 LOCAL
,
CASCADED
옵션을 지정하지 않았다면, 자동으로 CASCADED
옵션을 사용한다.
CHECK OPTION
옵션은 RECURSIVE
뷰에서는 사용하지 못할 수도 있다.
CHECK OPTION
옵션 기능은
INSTEAD OF
트리거나,
INSTEAD
룰을 지정하지 않은
자동으로 업데이트 가능한 뷰만을 대상으로 작동된다.
만들고자 하는 뷰의 기반이 되는 뷰에서
INSTEAD OF
트리거를 사용하고 있다면,
새로 만들 뷰에 LOCAL CHECK OPTION
옵션을 지정해야 할 것이다. 그렇지 않으면,
그 기반 뷰에 지정한 INSTEAD OF
트리거를
검사하지 않게 된다. (CASCADED CHECK OPTION
옵션은 트리거가 있는 뷰에서는 작동하지 않고, 그에 따라
이런 모든 조건 검사가 다 무시 될 것이다.)
만들고자 하는 뷰나, 그 기반이 되는 모든 개체들에
INSTEAD
룰이 있다면,
INSERT
, UPDATE
작업은
그 체크 옵션 설정은 모두 그 룰 기반 처리에 의해 무시된다.
뷰를 삭제할 때는 DROP VIEW 명령을 사용한다.
뷰를 만들 때, 그 칼럼 이름을 지정하는 것에 주의해야 한다. 다음이 이런 예다:
CREATE VIEW vista AS SELECT 'Hello World';
이런 형태로 뷰를 만들게 되면, 그 뷰의 칼럼으로
?column?
이름의 칼럼이 보이게 된다.
그 칼럼의 자료형은 특별히 지정하지 않았음에도 불구하고,
text
형이 된다. 이런 문제를 피하기 위해서는
다음과 같이 자료형과 칼럼 이름을 쿼리에 명시적으로 지정하면 된다:
CREATE VIEW vista AS SELECT text 'Hello World' AS hello;
해당 뷰가 참조하는 테이블의 접근권한은 그 뷰 소유주의 접근권한에 따라 결정된다. 경우에 따라, 보안상의 이유로 그 참조하는 테이블에 대해서 접근권한을 제한 할 수도 있다. 하지만, 모든 뷰가 이런 접근 권한 정책으로 자료를 안전하게 관리할 수 있는 것은 아니다. 40.5절에서 이 부분을 자세히 다룬다. 예를 들어 뷰 안에 있는 함수는 그 뷰 소유주의 권한으로 실행된다. 따라서 그 뷰의 사용자는 그 뷰 안에 있는 함수를 사용할 수 있는 권한이 있어야한다. (이런 복잡한 상황 때문에, 뷰를 만들 때는 권한 관련 부분을 꼼꼼히 살펴보아야 한다. - 옮긴이)
기존에 있는 뷰를 대상으로 CREATE OR REPLACE VIEW
명령으로 바꿀 때는 단지 SELECT 작업에 대한 내용만 바꾼다.
뷰 속성, 소유주, 접근권한, SELECT 작업이 아닌 룰 등은 바뀌지 않는다.
또한 이 작업은 그 뷰의 소유주만 할 수 있다. (물론 그 소유주의
소속원도 포함해서)
간단한 뷰는 그 자료 갱신이 가능하다: 즉, 뷰를 대상으로
INSERT
, UPDATE
,
DELETE
구문을 사용해서 그 뷰가 사용하는
실 테이블의 자료를 갱신할 수 있다. 다음 모든 조건을
만족한다면, 그 뷰는 업데이트가 가능하다:
뷰를 정의하는 쿼리의 FROM
목록에
하나의 개체만(테이블이거나 또 다른 업데이트 가능한 뷰이거나)
지정된 경우.
뷰 정의 쿼리에, WITH
, DISTINCT
,
GROUP BY
, HAVING
,
LIMIT
, 또는 OFFSET
구문이 없는
경우.
뷰 정의 쿼리에 집합 연산(UNION
,
INTERSECT
또는 EXCEPT
)이 없는
경우.
뷰 정의 쿼리의 칼럼 출력 부분에, 집계 함수, 윈도우 함수, 집합 반환 함수가 없는 경우.
자동 업데이트 가능한 뷰는 업데이트 가능한 칼럼과 그렇지 못하는
칼럼을 함께 사용할 수 있다. 해당 칼럼이 업데이트 가능한 것이라면 (
위 조건을 만족하는 경우), 그 칼럼을 조작하는 DML 구문에 대해서는
처리가 가능하고, 그렇지 않는 경우는 읽기 전용 칼럼으로 처리해서,
이 읽기 전용 칼럼에 대한 INSERT
또는
UPDATE
구문을 사용한다면 오류로 처리한다.
자동 업데이트 가능한 뷰를 대상으로 INSERT
,
UPDATE
또는 DELETE
구문을
사용하게 되면, 내부적으로 그 대상이 되는 실 테이블을 대상으로
쿼리가 바뀌어 실행된다.
INSERT
구문에서는 ON
CONFLICT UPDATE
구문도 잘 지원한다.
자동 업데이트 가능한 뷰에 WHERE
조건이
있는 경우라면, UPDATE
, DELETE
명령인 경우, 그 조건이 그대로 실 테이블에 적용된다.
또한, UPDATE
구문인 경우, 변경된 뒤 값이
WHERE
조건에 맞지 않는 경우는 더 이상
해당 뷰를 통해서는 그 자료를 볼 수 없게 된다. 한편,
INSERT
명령은 일단 WHERE
조건과 관계 없이 자료가 입력은 되고, (ON CONFLICT UPDATE
구문에 의해서 자료가 바뀔 수도 있고) 다음
뷰 조회에서 WHERE
조건으로 보이지 않을 수 있다.
이 문제를 방지하려면, CHECK OPTION
옵션을 사용해서
INSERT
, UPDATE
명령에서
자료 변경을 제한할 수도 있다.
자동 업데이트 가능한 뷰에 security_barrier
옵션을 지정했다면, WHERE
조건 및
LEAKPROOF
옵션이 있는 연산자를 사용하는 경우
항상 가장 먼저 그 조건을 먼저 검사한다. 이 부분에 대해서는
40.5절에서 자세히 다룬다. 기억해야 할 점은
rows which are not ultimately returned (because they do not
pass the user's WHERE
conditions) may still end up being locked 이것이다.
이 부분은 EXPLAIN
명령을 통해서,
어떤 조건이 먼저 적용되었는지 살펴 볼 수 있다.
그 외, 보다 복잡한 뷰는 일반적으로 대부분 읽기 전용 뷰가 된다. 이 뷰를
통해서는 자료 입력, 수정, 삭제는 할 수 없다. 이런 뷰도
INSTEAD OF
트리거를 지정하면, 원한는 자료 변경
작업을 할 수는 있다. 예를 들어, 이 뷰에 자료를 입력하면,
저 테이블에 그 값을 입력하는 방식으로 구현할 수 있다. 트리거에
대한 자세한 설명은 CREATE TRIGGER 명령 설명서에
다룬다. 또 다른 한 방법으로 룰(CREATE RULE 참조)을
만들어 이 부분을 처리할 수도 있지만, 트리거가 좀 더 구현하기 쉽고,
의도하는 대로 작동한다.
뷰를 통한 자료 입력, 변경, 삭제 작업을 하려면, 그 뷰에 대해서 적절한 권한이 있어야 함을 기억해야 한다. 일반적으로 뷰의 소유주가 기본적으로 이 권한을 갖고 있지만, 다른 사용자가 그 뷰를 통해서 자료를 변경 하려고 한다면, 그 뷰가 사용하는 실 테이블이 아니라, 그 뷰 자체에 대한 그 권한이 있어야 한다(40.5절 참조).
모든 코미디 영화를 보여주는 뷰 만들기.
CREATE VIEW comedies AS SELECT * FROM films WHERE kind = 'Comedy';
이 명령은 해당 뷰를 만드는 시점의 film
테이블의
칼럼을 기반으로 뷰에서 사용하는 칼럼이 결정된다.
*
칼럼 정의를 했다 하더라도, 그렇다. 즉 뷰를 만든
다음 테이블에 새 칼럼이 추가 되어도 뷰에는 추가되지 않는다.
LOCAL CHECK OPTION
옵션을 사용하는 뷰:
CREATE VIEW universal_comedies AS SELECT * FROM comedies WHERE classification = 'U' WITH LOCAL CHECK OPTION;
이 명령은 앞에서 만든 뷰를 기반으로 classification = 'U'
조건을 만족하는 자료를 대상으로만 하는 또 다른 뷰를 만든다.
이 뷰에서 INSERT
또는 UPDATE
명령을 사용하는 경우, 단지 classification = 'U'
조건을 만족하는지만 검사하지, 그 기반이 된 comedies 뷰의 제한한
kind = 'Comedy'
조건을 만족하는지는 검사하지 않는다.
CASCADED CHECK OPTION
옵션을 사용하는 뷰:
CREATE VIEW pg_comedies AS SELECT * FROM comedies WHERE classification = 'PG' WITH CASCADED CHECK OPTION;
이 뷰는 두 조건 모두를 만족하는지 검사한다.
업데이트 가능한 칼럼과 가능하지 않는 칼럼이 함께 있는 뷰:
CREATE VIEW comedies AS SELECT f.*, country_code_to_name(f.country_code) AS country, (SELECT avg(r.rating) FROM user_ratings r WHERE r.film_id = f.id) AS avg_rating FROM films f WHERE f.kind = 'Comedy';
이 뷰를 대상으로 INSERT
, UPDATE
,
DELETE
명령을 사용할 수 있다. films
테이블의 모든 칼럼에 대해서는 업데이트 가능하지만,
country
, avg_rating
같은 계산된
칼럼은 업데이트 할 수 없다.
1부터 100까지 출력하는 재귀형 뷰 만들기:
CREATE RECURSIVE VIEW public.nums_1_100 (n) AS VALUES (1) UNION ALL SELECT n+1 FROM nums_1_100 WHERE n < 100;
이 예제에서는 스키마 이름 사용법에 주의해야 한다. CREATE
명령의 뷰 이름에는 스키마 이름을 지정할 수 있지만,
그 뷰에서 사용하는 쿼리 안에서 사용하는 재귀 호출용 뷰 이름에는
스키마 이름을 지정할 수 없다. CTE 이름에는 스키마 이름을 지정할 수
없기 때문이다.
CREATE OR REPLACE VIEW
구문은
PostgreSQL 확장형이다.
임시 뷰와
WITH ( ... )
구문도 확장형이다.