視圖是資料庫中一種虛擬的表格,它基於一個或多個實際表格的查詢結果而創建。它可以被視為一個預先定義的查詢,具有獨立的名稱,方便查詢和使用。通過使用視圖,可以將複雜的查詢操作簡化為單個表格,提供更清晰、更易讀的數據視圖。視圖還可以用於控制對數據的訪問權限,只提供特定的數據子集給用戶或應用程序。它提供了更高的數據安全性和隱私保護。使用視圖可以提高數據庫的性能和維護性,同時提供更靈活的數據操作方式。
基本操作
新增、修改、刪除視圖(View)的指令也是使用SQL中常使用的三種「資料定義語言」(Data Definition Language,DDL)CREATE
、ALTER
、DROP
來操作。
新增視圖
新增視圖(View)有兩種方式,一種是使用了重複的視圖名稱會拋出錯誤訊息停止執行指令,可以避免覆蓋掉已經建立好的視圖。另一種指令是名稱重複的話會直接覆蓋掉舊版視圖,可依照需求使用。
-- 如果名稱重複會拋出錯誤訊息,可避免覆蓋
CREATE VIEW view_name AS ...;
-- 如果名稱重複會覆蓋
CREATE OR REPLACE VIEW view_name AS ...;
編輯視圖
建立好的視圖(View)可以再修改,但是ALTER VIEW
指令找不到指定的視圖會拋出錯誤訊息,所以也可以使用剛才提到的CREATE OR REPLACE
來修改。
-- 如果找不到指定VIEW會拋出錯誤訊息
ALTER VIEW view_name AS ...;
刪除視圖
以下提供兩種刪除視圖(View)的方式,第一種指令會在找不到指定名稱的視圖的時候拋出錯誤,讓後續指令無法執行。第二種指令會在找不到的情況下直接執行完畢,只留下一個警告訊息,然後繼續執行下一行指令(如果有)。
-- 如果找不到會拋出錯誤訊息
DROP VIEW view_name;
-- 顯示:ERROR 4092 (42S02): Unknown VIEW: 'test.view_name'
-- 如果找不到也能順利執行指令
DROP VIEW IF EXISTS view_name;
-- 顯示:Query OK, 0 rows affected, 1 warning (0.006 sec)
查詢現有試圖
可以透過SHOW TABLES
來看目前的視圖,可是會跟普通的資料表混在一起不好分辨,所以可以用另一個指令SHOW FULL TABLES
,這樣就可以清楚看出目前有哪些視圖了。
SHOW FULL TABLES;
查詢視圖結構
跟查詢資料表結構一樣,可以透過以下SQL查詢。
-- 顯示欄位結構
DESC view_name;
-- 顯示CEATE VIEW SQL
SHOW CREATE VIEW view_name;
實際操作
建立範例資料
我們使用之前的 3-4資料表正規化 教學中經過正規化過後的資料表結構,作為這次視圖操作的範例資料表與範例資料。
-- https://klab.tw/2023/05/database-teaching-7-1/
CREATE DATABASE test;
USE test;
CREATE TABLE IF NOT EXISTS 時區資料表 (
地點 VARCHAR(20) PRIMARY KEY,
時區 VARCHAR(20)
);
CREATE TABLE IF NOT EXISTS 部門資料表 (
部門ID INT PRIMARY KEY,
部門名稱 VARCHAR(20),
部門地點 varchar(20),
FOREIGN KEY(部門地點) REFERENCES 時區資料表(地點)
);
CREATE TABLE IF NOT EXISTS 員工資料表 (
員工ID INT PRIMARY KEY,
員工姓名 VARCHAR(20),
部門ID VARCHAR(20),
FOREIGN KEY(部門ID) REFERENCES 部門資料表(部門ID)
);
CREATE TABLE IF NOT EXISTS 員工語言表 (
員工ID INT,
語言 VARCHAR(20),
PRIMARY KEY(員工ID, 語言),
FOREIGN KEY(員工ID) REFERENCES 員工資料表(員工ID)
);
INSERT INTO 時區資料表 VALUES ('台北', 'UTC+8'), ('東京', 'UTC+9');
INSERT INTO 部門資料表 VALUES (1, '業務部', '台北'), (2, '研發部', '東京');
INSERT INTO 員工資料表 VALUES (1, 'Kyle', 1), (2, 'Stitch', 1), (3, 'Sato', 2);
INSERT INTO 員工語言表 VALUES (1, '中文'), (1, '英文'), (1, '日文'), (2, '中文'), (3, '英文'), (3, '日文');
建立部門視圖
我們建立一個部門視圖,可以同時查詢部門資料、時區資料、部門人數。
CREATE VIEW 部門視圖 AS
SELECT
d.部門ID, 部門名稱,
COUNT(d.部門ID) AS 部門人數,
部門地點, t.時區
FROM 部門資料表 AS d
LEFT JOIN 時區資料表 AS t ON d.部門地點=t.地點
LEFT JOIN 員工資料表 AS u ON d.部門ID=u.部門ID
GROUP BY d.部門ID;
這邊使用left join來合併查詢時區資料表與員工資料表,使用left是避免部門沒有時區資料,或是沒有任何員工的情況下就不會顯示出來。使用left join代表只要有部門就要顯示,如果沒有時區就會顯示null,如何沒有部門員工COUNT(d.部門ID)就會顯示0,以便確保我們能看見所有部門資料。這些在JOIN查詢的教學會有更多資訊。
從上面可以看出來CREATE VIEW 部門視圖 AS的下面接著平常使用的select語句就可以建立視圖了,我們可以使用以下方式來使用我們建立好的視圖。
SELECT * FROM 部門視圖;
因為他是一張虛擬的資料表,所以平常對資料表可以使用的where
、group
、order
等SQL在這邊依然可以使用。
建立員工視圖
我們建立一個員工視圖,可以同時查詢員工資料、部門名稱、員工會的語言。
CREATE VIEW 員工視圖 AS
SELECT
u.員工ID, 員工姓名,
CONCAT(部門地點, ' - ', 部門名稱) AS 部門,
COUNT(s.語言) AS 語言數量,
GROUP_CONCAT(s.語言) AS 語言
FROM 員工資料表 AS u
LEFT JOIN 部門資料表 AS d on d.部門ID=u.部門ID
LEFT JOIN 員工語言表 AS s on s.員工ID=u.員工ID
GROUP BY u.員工ID;
這邊整合了三張資料表,讓我們查詢員工資料表就能透過CONCAT
清楚看見部門地點與名稱、透過COUNT
計算會多少種語言,還透過GROUP_CONCAT
把每一種語言列出來。
我們透過視圖把一堆資料表的資料變回當初做正規化之前所有資料都塞在一起的模樣,查詢起來會比較方便,可是實際的資料依然是正規化的乾淨、單一、好維護的結構,是不是很方便呢!各位也可以試試看,要如何修改才能把時區資料也一併放到員工視圖上。
使用起來也很簡單。
SELECT * FROM 員工視圖;
因為他是一張虛擬的資料表,所以平常對資料表可以使用的where
、group
、order
等SQL在這邊依然可以使用。
可寫資料的視圖
除了方便我們SELECT
之外,VIEW也可以用來INSERT
、UPDATE
、DELETE
,但是必須滿足一些條件。
INSERT
- 只有當 View 的定義符合一定的條件時,才能對 View 進行 INSERT 操作。
- View 必須是基於單一資料表的簡單 SELECT 查詢,並且不能包含以下元素:GROUP BY、HAVING、UNION、DISTINCT、聚合函數、子查詢、計算欄位、LIMIT。
- View 必須包含對應的 UNIQUE 或 PRIMARY KEY 索引,且這些索引的每個欄位都必須是可寫的。
UPDATE
- View 必須符合 INSERT 操作的條件,即只能是基於單一資料表的簡單 SELECT 查詢。
- View 的定義不能使用聚合函數、GROUP BY、HAVING、DISTINCT、UNION、子查詢、計算欄位。
- View 必須包含對應的 UNIQUE 或 PRIMARY KEY 索引,且這些索引的每個欄位都必須是可寫的。
DELETE
- View 必須符合 INSERT 和 UPDATE 操作的條件,即只能是基於單一資料表的簡單 SELECT 查詢。
- View 的定義不能使用聚合函數、GROUP BY、HAVING、DISTINCT、UNION、子查詢、計算欄位。
- View 必須包含對應的 UNIQUE 或 PRIMARY KEY 索引,且這些索引的每個欄位都必須是可寫的。
更多應用
在後面的教學會提到資料庫帳號權限的應用。例如我們需要給一個人,或是一個應用程式比較小的權限,讓他只能觀看特地資料表中的特定資料。那麽我們也可以把這些資料集中起來做成一個視圖,然後讓那個小權限的帳號只能讀取這個視圖,就能從資料庫權限控管上保護資料的隱私與安全。