第14章 MySQL視圖詳解


第14章 MySQL視圖詳解


1. 常見的數據庫對象

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

2. 視圖概述

1555430281798

2.1 為什么使用視圖?

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

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

2.2 視圖的理解

  • 視圖是一種虛擬表,本身是不具有數據的,占用很少的內存空間,它是 SQL 中的一個重要概念。

  • 視圖建立在已有表的基礎上, 視圖賴以建立的這些表稱為基表

    image-20211006211206990
  • 視圖的創建和刪除只影響視圖本身,不影響對應的基表。但是當對視圖中的數據進行增加、刪除和修改操作時,數據表中的數據會相應地發生變化,反之亦然。

  • 向視圖提供數據內容的語句為 SELECT 語句, 可以將視圖理解為存儲起來的 SELECT 語句

    • 在數據庫中,視圖不會保存數據,數據真正保存在數據表中。當對視圖中的數據進行增加、刪除和修改操作時,數據表中的數據會相應地發生變化;反之亦然。
  • 視圖,是向用戶提供基表數據的另一種表現形式。通常情況下,小型項目的數據庫可以不使用視圖,但是在大型項目中,以及數據表比較復雜的情況下,視圖的價值就凸顯出來了,它可以幫助我們把經常查詢的結果集放到虛擬表中,提升使用效率。理解和使用起來都非常方便。

3. 創建視圖

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

3.1 創建單表視圖

舉例:

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

查詢視圖:

SELECT *
FROM	salvu80;
1555430882363

舉例:

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語句中給字段取了別名,那么視圖中的字段名和別名相同。

3.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.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. 更新視圖的數據

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)

5.2 不可更新的視圖

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

  • 在定義視圖的時候指定了“ALGORITHM = TEMPTABLE”,視圖將不支持INSERT和DELETE操作;
  • 視圖中不包含基表中所有被定義為非空又未指定默認值的列,視圖將不支持INSERT操作;
  • 在定義視圖的SELECT語句中使用了JOIN聯合查詢,視圖將不支持INSERT和DELETE操作;
  • 在定義視圖的SELECT語句后的字段列表中使用了數學表達式子查詢,視圖將不支持INSERT,也不支持UPDATE使用了數學表達式、子查詢的字段值;
  • 在定義視圖的SELECT語句后的字段列表中使用DISTINCT聚合函數GROUP BYHAVINGUNION等,視圖將不支持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. 修改、刪除視圖

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
查詢語句

6.2 刪除視圖

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

  • 刪除視圖的語法是:

    DROP VIEW IF EXISTS 視圖名稱;
    
    DROP VIEW IF EXISTS 視圖名稱1,視圖名稱2,視圖名稱3,...;
    
  • 舉例:

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

7. 總結

7.1 視圖優點

1. 操作簡單

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

2. 減少數據冗余

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

3. 數據安全

MySQL將用戶對數據的訪問限制在某些數據的結果集上,而這些數據的結果集可以使用視圖來實現。用戶不必直接查詢或操作數據表。這也可以理解為視圖具有隔離性。視圖相當於在用戶和實際的數據表之間加了一層虛擬表。

image-20211010211744459

同時,MySQL可以根據權限將用戶對數據的訪問限制在某些視圖上,用戶不需要查詢數據表,可以直接通過視圖獲取數據表中的信息。這在一定程度上保障了數據表中數據的安全性。

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

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

7.2 視圖不足

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

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

所以,在創建視圖的時候,你要結合實際項目需求,綜合考慮視圖的優點和不足,這樣才能正確使用視圖,使系統整體達到最優。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM