視圖

視圖

1. 常見的數據庫對象

對象 描述
表(TABLE) 表是存儲數據的邏輯單元,以行和列的形式存在,列就是字段,行就是記錄
數據字典 就是系統表,存放數據庫相關信息的表。系統表的數據通常由數據庫系統維護,程序員通常不應該修改,只可查看
約束(CONSTRAINT) 執行數據校驗的規則,用于保證數據完整性的規則
視圖(VIEW) 一個或者多個數據表里的數據的邏輯顯示,視圖并不存儲數據
索引(INDEX) 用于提高查詢性能,相當于書的目錄
存儲過程(PROCEDURE) 用于完成一次完整的業務處理,沒有返回值,但可通過傳出參數將多個值傳給調用環境
存儲函數(FUNCTION) 用于完成一次特定的計算,具有一個返回值
觸發器(TRIGGER) 相當于一個事件監聽器,當數據庫發生特定事件后,觸發器被觸發,完成相應的處理

2. 視圖概述

202403151722619.png

1. 為什么使用視圖

視圖一方面可以幫我們使用表的一部分而不是所有的表,另一方面也可以針對不同的用戶制定不同的查詢視圖。比如,針對一個公司的銷售人員,我們只想給他看部分數據,而某些特殊的數據,比如采購的價格,則不會提供給他。再比如,人員薪酬是個敏感的字段,那么只給某個級別以上的人員開放,其他人的查詢視圖中則不提供這個字段。

剛才講的只是視圖的一個使用場景,實際上視圖還有很多作用。最后,我們總結視圖的優點。

2. 視圖的理解

  • 視圖是一種虛擬表,本身是不具有數據的,占用很少的內存空間,它是 SQL 中的一個重要概念。
  • 視圖建立在已有表的基礎上, 視圖賴以建立的這些表稱為基表。
202403151724097.png
  • 視圖的創建和刪除只影響視圖本身,不影響對應的基表。但是當對視圖中的數據進行增加、刪除和修改操作時,數據表中的數據會相應地發生變化,反之亦然
  • 向視圖提供數據內容的語句為 SELECT 語句, 可以將視圖理解為存儲起來的 SELECT 語句
    • 在數據庫中,視圖不會保存數據,數據真正保存在數據表中。當對視圖中的數據進行增加、刪除和修改操作時,數據表中的數據會相應地發生變化;反之亦然。
  • 視圖,是向用戶提供基表數據的另一種表現形式。通常情況下,小型項目的數據庫可以不使用視圖,但是在大型項目中,以及數據表比較復雜的情況下,視圖的價值就凸顯出來了,它可以幫助我們把經常查詢的結果集放到虛擬表中,提升使用效率。理解和使用起來都非常方便。

3. 創建視圖

  • CREATE VIEW 語句中嵌入子查詢

    CREATE [OR REPLACE] 
    [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
    VIEW 視圖名稱 [(字段列表)] 
    AS 查詢語句 [WITH [CASCADED|LOCAL] CHECK OPTION]
    
  • 精簡版

    CREATE VIEW 視圖名稱 
    AS 查詢語句
    

1. 創建單表視圖

舉例:

CREATE VIEW empvu80 
AS
SELECT employee_id, last_name, salary 
FROM employees 
WHERE department_id = 80;

查詢視圖:

SELECT * FROM salvu80;
202403151728284.png
CREATE VIEW emp_year_salary (
  ename,year_salary
) 
AS
SELECT ename,salary*12*(1+IFNULL(commission_pct,0)) 
FROM t_employee;

舉例:

CREATE VIEW salvu50 
AS
SELECT employee_id ID_NUMBER, last_name NAME,salary*12 ANN_SALARY 
FROM employees 
WHERE department_id = 50;

說明1:實際上就是我們在 SQL 查詢語句的基礎上封裝了視圖 VIEW,這樣就會基于 SQL 語句的結果集形成一張虛擬表。

說明2:在創建視圖時,沒有在視圖名后面指定字段列表,則視圖中字段列表默認和SELECT語句中的字段列表一致。如果SELECT語句中給字段取了別名,那么視圖中的字段名和別名相同。

2. 創建多表聯合視圖

舉例:

CREATE VIEW empview 
AS
SELECT employee_id emp_id,last_name NAME,department_name 
FROM employees e,departments d 
WHERE e.department_id = d.department_id;


CREATE VIEW emp_dept 
AS
SELECT ename,dname 
FROM t_employee 
LEFT JOIN t_department ON t_employee.did = t_department.did;


CREATE VIEW dept_sum_vu (name, minsal, maxsal, avgsal) 
AS
SELECT d.department_name, MIN(e.salary), MAX(e.salary),AVG(e.salary) 
FROM employees e, departments d
WHERE e.department_id = d.department_id 
GROUP BY d.department_name;
  • 利用視圖對數據進行格式化

    我們經常需要輸出某個格式的內容,比如我們想輸出員工姓名和對應的部門名,對應格式為emp_name(department_name),就可以使用視圖來完成數據格式化的操作:

    CREATE VIEW emp_depart 
    AS
    SELECT CONCAT(last_name,'(',department_name,')') AS emp_dept 
    FROM employees e 
    JOIN departments d 
    WHERE e.department_id = d.department_id
    

3. 基于視圖創建視圖

當我們創建好一張視圖之后,還可以在它的基礎上繼續創建視圖。

舉例:聯合“emp_dept”視圖和“emp_year_salary”視圖查詢員工姓名、部門名稱、年薪信息創建 “emp_dept_ysalary”視圖。

CREATE VIEW emp_dept_ysalary 
AS
SELECT emp_dept.ename,dname,year_salary 
FROM emp_dept 
INNER JOIN emp_year_salary ON emp_dept.ename = emp_year_salary.ename;

4. 查看視圖

語法1:查看數據庫的表對象、視圖對象

SHOW TABLES;

語法2:查看視圖的結構

DESC / DESCRIBE 視圖名稱;

語法3:查看視圖的屬性信息

# 查看視圖信息(顯示數據表的存儲引擎、版本、數據行數和數據大小等) 
SHOW TABLE STATUS LIKE '視圖名稱'\G

執行結果顯示,注釋Comment為VIEW,說明該表為視圖,其他的信息為NULL,說明這是一個虛表。

語法4:查看視圖的詳細定義信息

SHOW CREATE VIEW 視圖名稱;

5. 更新視圖的數據

1. 一般情況

MySQL支持使用INSERT、UPDATE和DELETE語句對視圖中的數據進行插入、更新和刪除操作。當視圖中的數據發生變化時,數據表中的數據也會發生變化,反之亦然。

舉例:UPDATE操作

mysql> SELECT ename,tel FROM emp_tel WHERE ename = '孫洪亮'; 
+---------+-------------+
| ename | tel | 
+---------+-------------+
| 孫洪亮 | 13789098765 | 
+---------+-------------+
1 row in set (0.01 sec) 

mysql> UPDATE emp_tel SET tel = '13789091234' WHERE ename = '孫洪亮'; 
Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0

mysql> SELECT ename,tel FROM emp_tel WHERE ename = '孫洪亮';
+---------+-------------+
| ename | tel | 
+---------+-------------+
| 孫洪亮 | 13789091234 | 
+---------+-------------+
1 row in set (0.00 sec) 

mysql> SELECT ename,tel FROM t_employee WHERE ename = '孫洪亮'; 
+---------+-------------+
| ename | tel | 
+---------+-------------+
| 孫洪亮 | 13789091234 | 
+---------+-------------+
1 row in set (0.00 sec)

舉例:DELETE操作

mysql> SELECT ename,tel FROM emp_tel WHERE ename = '孫洪亮'; 
+---------+-------------+
| ename | tel | 
+---------+-------------+
| 孫洪亮 | 13789091234 | 
+---------+-------------+
1 row in set (0.00 sec) 

mysql> DELETE FROM emp_tel WHERE ename = '孫洪亮';
Query OK, 1 row affected (0.01 sec) 

mysql> SELECT ename,tel FROM emp_tel WHERE ename = '孫洪亮'; 
Empty set (0.00 sec) 

mysql> SELECT ename,tel FROM t_employee WHERE ename = '孫洪亮'; 
Empty set (0.00 sec)

2. 不可更新的視圖

要使視圖可更新,視圖中的行和底層基本表中的行之間必須存在一對一的關系。另外當視圖定義出現如下情況時,視圖不支持更新操作:

  • 在定義視圖的時候指定了“ALGORITHM = TEMPTABLE”,視圖將不支持INSERT和DELETE操作;
  • 視圖中不包含基表中所有被定義為非空又未指定默認值的列,視圖將不支持INSERT操作;
  • 在定義視圖的SELECT語句中使用了 JOIN聯合查詢 ,視圖將不支持INSERT和DELETE操作;
  • 在定義視圖的SELECT語句后的字段列表中使用了 數學表達式 或 子查詢 ,視圖將不支持INSERT,也不支持UPDATE使用了數學表達式、子查詢的字段值;
  • 在定義視圖的SELECT語句后的字段列表中使用 DISTINCT 、 聚合函數 、 GROUP BY 、 HAVING 、 UNION 等,視圖將不支持INSERT、UPDATE、DELETE
  • 在定義視圖的SELECT語句中包含了子查詢,而子查詢中引用了FROM后面的表,視圖將不支持 INSERT、UPDATE、DELETE;
  • 視圖定義基于一個不可更新視圖;
  • 常量視圖。

舉例:

mysql> CREATE OR REPLACE VIEW emp_dept
 (ename,salary,birthday,tel,email,hiredate,dname)
 AS SELECT ename,salary,birthday,tel,email,hiredate,dname
 FROM t_employee INNER JOIN t_department
 ON t_employee.did = t_department.did ; 
Query OK, 0 rows affected (0.01 sec)


mysql> INSERT INTO emp_dept(ename,salary,birthday,tel,email,hiredate,dname) VALUES('張三',15000,'1995-01-08','18201587896', 'zs@atguigu.com','2022-02-14','新部門');

#ERROR 1393 (HY000): Can not modify more than one base table through a join view 'atguigu_chapter9.emp_dept'

從上面的SQL執行結果可以看出,在定義視圖的SELECT語句中使用了JOIN聯合查詢,視圖將不支持更新操作。

注意:雖然可以更新視圖數據,但總的來說,視圖作為虛擬表,主要用于方便查詢,不建議更新視圖的數據。對視圖數據的更改,都是通過對實際數據表里數據的操作來完成的。

6. 修改、刪除視圖

1. 修改視圖

方式1:使用CREATE OR REPLACE VIEW 子句修改視圖

CREATE OR REPLACE VIEW empvu80 (
  id_number, name, sal, department_id
) 
AS
SELECT employee_id, first_name || ' ' || last_name, salary, department_id 
FROM employees 
WHERE department_id = 80;

說明:CREATE VIEW 子句中各列的別名應和子查詢中各列相對應。

方式2:ALTER VIEW

修改視圖的語法是:

ALTER VIEW 視圖名稱 
AS
查詢語句

2. 刪除視圖

  • 刪除視圖只是刪除視圖的定義,并不會刪除基表的數據。

  • 刪除視圖的語法是:

    DROP VIEW IF EXISTS 視圖名稱;
    
  • 舉例:

    DROP VIEW empvu80;
    
  • 說明:基于視圖a、b創建了新的視圖c,如果將視圖a或者視圖b刪除,會導致視圖c的查詢失敗。這樣的視圖c需要手動刪除或修改,否則影響使用。

7. 總結

1. 視圖優點

  1. 操作簡單

將經常使用的查詢操作定義為視圖,可以使開發人員不需要關心視圖對應的數據表的結構、表與表之間的關聯關系,也不需要關心數據表之間的業務邏輯和查詢條件,而只需要簡單地操作視圖即可,極大簡化了開發人員對數據庫的操作。

  1. 減少數據冗余

視圖跟實際數據表不一樣,它存儲的是查詢語句。所以,在使用的時候,我們要通過定義視圖的查詢語句來獲取結果集。而視圖本身不存儲數據,不占用數據存儲的資源,減少了數據冗余。

  1. 數據安全

MySQL將用戶對數據的 訪問限制 在某些數據的結果集上,而這些數據的結果集可以使用視圖來實現。用戶不必直接查詢或操作數據表。這也可以理解為視圖具有 隔離性 。視圖相當于在用戶和實際的數據表之間加了一層虛擬表。同時,MySQL可以根據權限將用戶對數據的訪問限制在某些視圖上,用戶不需要查詢數據表,可以直接通過視圖獲取數據表中的信息。這在一定程度上保障了數據表中數據的安全性。

202403151746283.png
  1. 適應靈活多變的需求

    當業務系統的需求發生變化后,如果需要改動數據表的結構,則工作量相對較大,可以使用視圖來減少改動的工作量。這種方式在實際工作中使用得比較多。

  2. 能夠分解復雜的查詢邏輯

    數據庫中如果存在復雜的查詢邏輯,則可以將問題進行分解,創建多個視圖獲取數據,再將創建的多個視圖結合起來,完成復雜的查詢邏輯。

2. 視圖不足

如果我們在實際數據表的基礎上創建了視圖,那么,如果實際數據表的結構變更了,我們就需要及時對相關的視圖進行相應的維護。特別是嵌套的視圖(就是在視圖的基礎上創建視圖),維護會變得比較復雜, 可讀性不好,容易變成系統的潛在隱患。因為創建視圖的 SQL 查詢可能會對字段重命名,也可能包含復雜的邏輯,這些都會增加維護的成本。

實際項目中,如果視圖過多,會導致數據庫維護成本的問題。

所以,在創建視圖的時候,你要結合實際項目需求,綜合考慮視圖的優點和不足,這樣才能正確使用視圖,使系統整體達到最優。
202403151722619.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容