視圖
1. 常見的數據庫對象
對象 | 描述 |
---|---|
表(TABLE) | 表是存儲數據的邏輯單元,以行和列的形式存在,列就是字段,行就是記錄 |
數據字典 | 就是系統表,存放數據庫相關信息的表。系統表的數據通常由數據庫系統維護,程序員通常不應該修改,只可查看 |
約束(CONSTRAINT) | 執行數據校驗的規則,用于保證數據完整性的規則 |
視圖(VIEW) | 一個或者多個數據表里的數據的邏輯顯示,視圖并不存儲數據 |
索引(INDEX) | 用于提高查詢性能,相當于書的目錄 |
存儲過程(PROCEDURE) | 用于完成一次完整的業務處理,沒有返回值,但可通過傳出參數將多個值傳給調用環境 |
存儲函數(FUNCTION) | 用于完成一次特定的計算,具有一個返回值 |
觸發器(TRIGGER) | 相當于一個事件監聽器,當數據庫發生特定事件后,觸發器被觸發,完成相應的處理 |
2. 視圖概述
1. 為什么使用視圖
視圖一方面可以幫我們使用表的一部分而不是所有的表,另一方面也可以針對不同的用戶制定不同的查詢視圖。比如,針對一個公司的銷售人員,我們只想給他看部分數據,而某些特殊的數據,比如采購的價格,則不會提供給他。再比如,人員薪酬是個敏感的字段,那么只給某個級別以上的人員開放,其他人的查詢視圖中則不提供這個字段。
剛才講的只是視圖的一個使用場景,實際上視圖還有很多作用。最后,我們總結視圖的優點。
2. 視圖的理解
- 視圖是一種虛擬表,本身是不具有數據的,占用很少的內存空間,它是 SQL 中的一個重要概念。
- 視圖建立在已有表的基礎上, 視圖賴以建立的這些表稱為基表。
- 視圖的創建和刪除只影響視圖本身,不影響對應的基表。但是當對視圖中的數據進行增加、刪除和修改操作時,數據表中的數據會相應地發生變化,反之亦然。
- 向視圖提供數據內容的語句為 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;
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. 視圖優點
- 操作簡單
將經常使用的查詢操作定義為視圖,可以使開發人員不需要關心視圖對應的數據表的結構、表與表之間的關聯關系,也不需要關心數據表之間的業務邏輯和查詢條件,而只需要簡單地操作視圖即可,極大簡化了開發人員對數據庫的操作。
- 減少數據冗余
視圖跟實際數據表不一樣,它存儲的是查詢語句。所以,在使用的時候,我們要通過定義視圖的查詢語句來獲取結果集。而視圖本身不存儲數據,不占用數據存儲的資源,減少了數據冗余。
- 數據安全
MySQL將用戶對數據的 訪問限制 在某些數據的結果集上,而這些數據的結果集可以使用視圖來實現。用戶不必直接查詢或操作數據表。這也可以理解為視圖具有 隔離性 。視圖相當于在用戶和實際的數據表之間加了一層虛擬表。同時,MySQL可以根據權限將用戶對數據的訪問限制在某些視圖上,用戶不需要查詢數據表,可以直接通過視圖獲取數據表中的信息。這在一定程度上保障了數據表中數據的安全性。
-
適應靈活多變的需求
當業務系統的需求發生變化后,如果需要改動數據表的結構,則工作量相對較大,可以使用視圖來減少改動的工作量。這種方式在實際工作中使用得比較多。
-
能夠分解復雜的查詢邏輯
數據庫中如果存在復雜的查詢邏輯,則可以將問題進行分解,創建多個視圖獲取數據,再將創建的多個視圖結合起來,完成復雜的查詢邏輯。
2. 視圖不足
如果我們在實際數據表的基礎上創建了視圖,那么,如果實際數據表的結構變更了,我們就需要及時對相關的視圖進行相應的維護。特別是嵌套的視圖(就是在視圖的基礎上創建視圖),維護會變得比較復雜, 可讀性不好,容易變成系統的潛在隱患。因為創建視圖的 SQL 查詢可能會對字段重命名,也可能包含復雜的邏輯,這些都會增加維護的成本。
實際項目中,如果視圖過多,會導致數據庫維護成本的問題。
所以,在創建視圖的時候,你要結合實際項目需求,綜合考慮視圖的優點和不足,這樣才能正確使用視圖,使系統整體達到最優。