CS/DB

[혼공SQL] 뷰

F12:) 2024. 1. 29. 23:39

   

테이블은 아니지만, 사용자가 테이블처럼 사용하는 데이터베이스의 개체 중 하나이다.

놀랍게도, 뷰의 실체는 SELECT 문이며, 뷰를 호출하는 순간 뷰에 있던 SELECT문이 호출되는 형태로 진행된다. 자세한 과정은 조금 뒤에서 다룬다.

 

뷰는 하나의 테이블과 연관되어 있을 때, 그러니까 JOIN을 사용하지 않았을 때 단순 뷰라고 부르며,

JOIN을 사용하여 여러 테이블과 연관되어 있을 때는 복합 뷰라고 부른다.

 

   뷰의 생성

뷰는 아래의 SQL문 형식으로 생성할 수 있다.

CREATE VIEW 뷰_이름
AS
	SELECT 문;

 

 

실제 예시를 확인해보자. member 테이블이 존재하는데, 그 중에서 원하는 column만 뽑아와서 뷰를 만든 것이다.

CREATE VIEW v_member
AS
	SELECT mem_id, mem_name, addr FROM member;

 

 

 

우리가 사용하는  SELECT문과 비슷하게, SELECT에 WHERE도 당연하게 넣을 수 있다. 아래는 원하는 값만 추출하여 뷰를 만든 형태이다.

SELECT mem_name, addr FROM v_member
	WHERE addr IN ('서울', '경기');

 

위 두 예제에서 볼 수 있듯이, 뷰를 생성할 때는 뷰임을 명확하게 알 수 있도록 이름 앞에 v_를 넣는 것이 일반적이다.

 

 

   뷰의 작동

뷰가 어떻게 작동되는 지를 알아보자.

 

  1. 사용자는 뷰에 조회 또는 변경문을 사용하여 실행한다.
  2. 뷰에서는 실제 테이블에 자신의 SELECT문과 함께 쿼리를 실행한다.
  3. 해당 쿼리의 결과를 뷰로 가져온다.
  4. 뷰는 해당 결과를 사용자에게 보여준다.

 

 

   뷰의 사용 이유

보안

뷰를 사용함으로써 실제 테이블을 숨길 수 있다. 원하는 특정 열만을 뽑아내거 뷰를 만들면 다른 민감한 정보를 노출시키지 않을 수 있기 때문에, 보안에서 이점이 있다.

 

SQL의 단순화

만약 뷰를 이용하지 않고 아래와 같은 복잡한 쿼리를 반복적으로 실행해야한다면 복잡하고 번거롭다.

SELECT B.mem_id, M.mem_name, B.prod_name,
			 M.addr, CONCAT(M.phone1, M.phone2) '연락처'
	FROM buy B
		INNER JOIN member M
		ON B.mem_id = M.mem_id;

 

그럴 때, 뷰를 만들어 사용하면 편리하다.

CREATE VIEW v_memberbuy
AS
	SELECT B.mem_id, M.mem_name, B.prod_name,
			 M.addr, CONCAT(M.phone1, M.phone2) '연락처'
		FROM buy B
			INNER JOIN member M
			ON B.mem_id = M.mem_id;

 

 

   뷰의 작동

뷰를 생성할 때, 참조하는 테이블의 이름과 다르게 열 이름을 지정할 수 있다. 뷰를 선언할 때 작성하는 SELECT문에 별칭(alias)를 사용함으로써 가능하다.

 

별칭은 한글, 띄어쓰기가 가능하지만 선언 후 뷰를 호출하고자 할 때, 띄어쓰기가 존재한다면 백틱(`)을 사용해 묶어주어야 한다.

또한 한글을 사용하게 되면, 한글을 지원하지 않는 OS에서는 오류가 있을 수 있으므로 권장하지 않는다.

CREATE VIEW v_viewtest1
AS
	SELECT B.mem_id 'Member ID', M.mem_name AS 'Member Name',
				 B.prod_name "Product Name", CONCAT(M.phone1, M.phone2) AS "Office Phone"
		FROM buy B
			INNER JOIN member M
			ON B.mem_id = M.mem_id;

SELECT DISTINCT `Member ID`, `Member Name` FROM v_viewtest1;

 

 

뷰를 수정하기 위해서는 ALTER TABLE과 유사한 ALTER VIEW를 사용한다. 

ALTER VIEW v_viewtest1
AS
	SELECT B.mem_id 'Member ID', M.mem_name AS 'Member Name',
				 B.prod_name "Product Name", CONCAT(M.phone1, M.phone2) AS "Office Phone"
		FROM buy B
			INNER JOIN member M
			ON B.mem_id = M.mem_id;

SELECT DISTINCT `Member ID`, `Member Name` FROM v_viewtest1;

 

 

뷰의 삭제는 DROP VIEW이다. 이처럼 테이블의 문법과 유사한 형태를 가지고 있음을 알 수 있다.

 

 

   뷰의 여러가지 키워드

뷰도 테이블과 마찬가지로, 기존에 있는 뷰와 같은 이름으로 생성하고자 한다면 오류가 발생한다. 이 때, CREATE OR REPLACE 키워드를 사용한다면, 기존 뷰가 삭제되고 새롭게 생성되는 작동을 한다.

 

DESCRIBE뷰의 정보를 확인할 수 있다(테이블도 가능하다). 하지만 DESCRIBE를 뷰에 사용하게 되면 PK의 정보가 표시되지 않는다.

 

SHOW CREATE VIEW로 뷰가 생성될 때의 소스코드를 확인해볼 수 있다.

 

 

   뷰 사용 시 주의점

만약 뷰가 참조하는 테이블(이하 참조 테이블)의 일부 열만을 참조한다고 하자. 이렇게 된다면 뷰를 통해서 데이터를 삽입하려고 할 때, 참조 테이블의 NOT NULL 조건이 있는 열을 뷰가 참조하지 않았다면 삽입이 불가능할 것이다.

 

이러한 경우에서는 아래와 같은 3가지 방법으로 해결할 수 있다.

  • 뷰에서 NOT NULL 열을 포함하도록 재정의
  • 참조 테이블에서 NOT NULL 속성인 열을 NULL로 바꾸기
  • 참조 테이블에 DEFAULT 키워드를 통해서, 뷰에서 값을 지정하지 않아도 자동으로 입력될 값 설정해주기

 

또 이러한 상황을 가정해보자. 만약 아래와 같이 height가  167 이상인 데이터만 가져올 수 있도록 뷰를 생성했다고 해보자.

CREATE VIEW v_height167
AS
	SELECT * FROM member WHERE height >= 167 ;

SELECT * FROM v_height167;

 

하지만 이와 반대로 우리가 데이터를 입력할 때, 167 미만의 데이터를 입력하게 된다면 어떻게 될까?

INSERT INTO v_height167 VALUES('TRA', '티아라', 160);

 

당연하게 정상적으로 수행될 것이다. 하지만 167 이상의 height만 조회할 수 있는 뷰에서 167 이하의 데이터를 입력하는 행위는 썩 좋지 않아보인다.

 

이럴 때, WITH CHECK OPTION을 활용하여 뷰에서 설정된 값의 범위가 벗어나는 값은 입력되지 못하게 설정할 수 있다.

ALTER VIEW v_height167
AS
	SELECT * FROM member WHERE height >= 167
			WITH CHECK OPTION;

INSERT INTO v_height167 VALUES('TOB', '텔레토비', 165);

이렇게 하게 된다면 167 미만의 데이터를 입력하여도 데이터가 입력되지 않는다.