簡介
什麼是視圖
視圖(View)是一種虛擬存在的表。其內容與真實的表相似,包含一系列帶有名稱的列和行數據。但是視圖並不在數據庫中以存儲的數據的形式存在。行和列的數據來自定義視圖時查詢所引用的基本表,並且在具體引用視圖時動態生成。
視圖的特點如下:
<1> 視圖的列可以來自不同的表,是表的抽象和在邏輯意義上建立的新關係;
<2> 視圖是由基本表(實表)產生的表(虛表);
<3> 視圖的建立和刪除不影響基本表;
<4> 對視圖內容的更新(增刪改)直接影響基本表;
<5> 當視圖來自多個基本表時,不允許添加和刪除數據。
爲什麼使用視圖
數據庫中關於數據的查詢有時候非常複雜,例如表連接、子查詢等,邏輯複雜,編寫語句比較多。當這種查詢需要重複使用時,則不會次次都能編寫正確,從而降低了數據庫的實用性。
在具體操作表前,有時候要求只能操作部分字段,而不是全部字段。例如,在公司中員工的工資一般是保密的,如果因爲程序員一時疏勿而向查詢中多寫入了“工資”的字段,則會讓員工的“工資”顯示給所有能夠查看該查詢結果的人,這時就需要限制程序員操作的字段。
視圖是程序員只關心感興趣的某些特定數據和他們所負責的特定任務。這樣程序員只能看到視圖中所定義的數據,而不是視圖所引用表中的數據,從而提高了數據庫的安全性。
視圖相對於普通的表的有時主要包括以下幾項:
<1> 簡單:使用視圖的用戶完全不需要關心視圖中的數據是通過什麼查詢得到的,視圖中的數據對用戶來說已經是過濾好的符合條件的結果集;
<2> 安全:使用視圖的用戶只能訪問他們被允許查詢的結果集,對錶的權限管理並不能限制到某個行或某個列,但是通過視圖就可以簡答地實現;
<3> 數據獨立:一旦視圖的結構確定了,可以屏蔽表結構變化對用戶的影響,原表增加列對視圖沒有影響;源表修改列名,則可以通過修改視圖來解決,不會造成對訪問者的影響。
視圖操作
視圖的操作包括創建視圖、查看視圖、刪除視圖和修改視圖。
創建視圖
依然是使用幫助命令? CREATE VIEW 找到官網的幫助地址:
http://dev.mysql.com/doc/refman/5.6/en/create-view.html
創建視圖的語法:
CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] [DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER }] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL] CHECK OPTION] |
提取出關鍵部分得到基本語法:
CREATE VIEW view_name AS select_statement;
意爲“使用查詢語句select_statement的查詢結果創建視圖view_name”。
CREATE VIEW代碼段創建一個新的視圖,或是在使用了OR REPLACE選項時嘗試替換一個已經存在的視圖。如果視圖view_name不存在,CREATE OR REPLACE VIEW 等同於CREATE VIEW,如果存在則等同於ALTERVIEW。
示例1,創建並使用簡單視圖:
<1> 創建視圖保存員工名和對應的部門名:
MySQL> CREATE OR REPLACE VIEW view_emp_with_deptname -> AS -> SELECT e.ename,d.deptname FROM emp e,dept d WHERE e.deptno=d.deptno; Query OK, 0 rows affected (0.02 sec) |
<2> 使用視圖,查詢出所有的數據:
mysql> SELECT * FROM view_emp_with_deptname; +--------+-----------+ | ename | deptname | +--------+-----------+ | 張三 |金融部 | | 李四 |金融部 | | 趙六 |金融部 | | 王五 |人事部 | | 周七 |事業部 | +--------+-----------+ 5 rows in set (0.00 sec) |
<3> 向emp表中插入一條數據,再次使用視圖:
mysql> SELECT * FROM view_emp_with_deptname; +--------+-----------+ | ename | deptname | +--------+-----------+ | 張三 |金融部 | | 李四 |金融部 | | 趙六 |金融部 | | 王五 |人事部 | | 周七 |事業部 | | 測試 |事業部 | +--------+-----------+ 6 rows in set (0.00 sec) |
可以發現查詢結果已經更新了。
示例2,使用視圖插入、修改、刪除表中數據:
<1> 創建視圖view_emp,插入數據,刪除數據,更新數據,查詢數據:
mysql> INSERT INTO view_emp VALUES('劉梅',22,3); Query OK, 1 row affected (0.01 sec)
mysql> DELETE FROM view_emp WHERE ename='測試'; Query OK, 1 row affected (0.02 sec)
mysql> UPDATE view_emp SET ename='張三三' WHERE ename='張三'; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM view_emp; +-----------+------+--------+ | ename | age | deptno | +-----------+------+--------+ | 張三三 | 21 | 1 | | 李四 | 22 | 1 | | 王五 | 27 | 2 | | 趙六 | 31 | 1 | | 周七 | 23 | 3 | | 孫八 | 37 | 5 | | 劉梅 | 22 | 3 | +-----------+------+--------+ 7 rows in set (0.00 sec) |
可以看到,操作都正確執行,且視圖中的數據也隨之更新。
<2> 查看emp表中的數據是否更新;
mysql> SELECT ename,age,deptno FROM emp; +-----------+------+--------+ | ename | age | deptno | +-----------+------+--------+ | 張三三 | 21 | 1 | | 李四 | 22 | 1 | | 王五 | 27 | 2 | | 趙六 | 31 | 1 | | 周七 | 23 | 3 | | 孫八 | 37 | 5 | | 劉梅 | 22 | 3 | +-----------+------+--------+ 7 rows in set (0.00 sec) |
同樣,基表emp中的數據由於對視圖的修改也得到了修改。
視圖的限制
使用視圖的限制信息請參考Section C.5, “Restrictions on Views”。整理爲以下幾點:
<1> 不能在視圖上創建索引;
<2> 在視圖的FROM子句中不能使用子查詢;
<3> 以下情形中的視圖是不可更新的(更新是指對基表中的數據進行更新,並不是指基表中數據修改後,視圖中的數據不進行更新或是不能對視圖的定義進行修改):
[1]包含以下關鍵字的SQL語句:聚合函數(SUM、MIN、MAX、COUNT等)、DISTINCT、GROUP BY、HAVING、UNION或UNION ALL;
[2]常量視圖;
[3]SELECT中包含子查詢;
[4]JOIN;
[5]FROM一個不能更新的視圖;
[6]WHERE子句的子查詢引用了FROM子句中的表。
注:
<1>不能在視圖上創建索引
最開始解釋視圖的概念時有這樣的描述“視圖並不在數據庫中以存儲的數據的形式存在。行和列的數據來自定義視圖時查詢所引用的基本表,並且在具體引用視圖時動態生成”,該描述結合索引“複製索引列值保存到內存中”的特點就可得到此限制的原因:視圖不是表或是臨時表,其中沒有可供索引複製的值。
<2>在視圖的FROM子句中不能使用子查詢
先看一下是否真的不允許:
mysql> CREATE VIEW view_t2 AS SELECT e.* FROM (SELECT * FROM emp) AS e; ERROR 1349 (HY000): View's SELECT contains a subquery in the FROM clause |
可以看到,確實明確的指出不允許在FROM子句中包含子查詢。
變通
雖然FROM子句中不能使用子查詢,但是可以先爲子查詢創建一個視圖,然後再從視圖中裝載數據:
mysql> CREATE VIEW view_t3 AS SELECT * FROM emp; Query OK, 0 rows affected (0.00 sec)
mysql> CREATE VIEW view_t2 AS SELECT * FROM view_t3; Query OK, 0 rows affected (0.02 sec)
mysql> SELECT * FROM view_t3; #省略 mysql> INSERT INTO view_t2 VALUES(NULL,'張鑫',33,3,250,'ZHANGXIN'); Query OK, 1 row affected (0.02 sec) |
無論是查詢還是修改基表中的數據都是正確執行的。
謹慎使用SELECT * 創建視圖
創建視圖時如果使用語句SELECT * FROMt…,需要小心,爲t增加一列,新增加的列不會反映到視圖中;但是,從t中刪除一列,使用視圖時會報錯。查看一下使用SELECT * FROM…創建的視圖的創建SQL就可以發現原因:
mysql> SHOW CREATE VIEW view_t3; ->| view_t3 | CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `view_t3` AS select `emp`.`id` AS `id`,`emp`.`ename` AS `ename`,`emp`.`age` AS `age`,`emp`.`deptno` AS `deptno`,`emp`.`salary` AS `salary`,`emp`.`phoneticize` AS `phoneticize` from `emp` | utf8 | utf8_general_ci | |
觀察灰色部分可以看到,MySQL將*翻譯成了創建視圖時基表中的每一個列名,但是在基表中增加或刪除列並不會更改視圖的創建信息,所以在基表中增加列或刪除列都不會反映到視圖中,且如果是刪除列,使用視圖時會報錯。
查看視圖
SHOW TABLES;
查看視圖的定義:
SHOW CREATE VIEW view_name;
刪除視圖
DROP VIEW [IF EXISTS] view_name [,…,view_name_n]…[RESTRICT|CASCADE];
修改視圖
方式一:先刪除再創建,使用語句CREATE OR REPLACE或是分步驟先DROP然後CREATE;
方式二:使用ALTER VIEW:
ALTERVIEW view_name as select_statement;