上集嘮叨了表中數據操做的一些語句,包括用於插入數據的INSERT
語句,用於刪除數據的DELETE
語句,用於更新數據的UPDATE
語句。不過咱們以前說到的增刪改查的語句都是一次性的,這些請求被包裝成請求被客戶端發到服務器,服務器處理後把結果返回給客戶端以後就沒有用了,本集將聚焦於如何讓這些一次性的語句變得能夠很容易的被重複使用。mysql
咱們以前嘮叨過鏈接表的查詢,比方說下邊這個:程序員
mysql> SELECT s1.number, s1.name, s1.major, s2.subject, s2.score FROM student_info AS s1 INNER JOIN student_score AS s2 WHERE s1.number = s2.number AND s1.sex = '男';
+----------+-----------+--------------------------+-----------------------------+-------+
| number | name | major | subject | score |
+----------+-----------+--------------------------+-----------------------------+-------+
| 20180101 | 杜子騰 | 計算機科學與工程 | 母豬的產後護理 | 78 |
| 20180101 | 杜子騰 | 計算機科學與工程 | 論薩達姆的戰爭準備 | 88 |
| 20180103 | 範統 | 軟件工程 | 母豬的產後護理 | 59 |
| 20180103 | 範統 | 軟件工程 | 論薩達姆的戰爭準備 | 61 |
+----------+-----------+--------------------------+-----------------------------+-------+
4 rows in set (0.00 sec)
mysql>
複製代碼
咱們查詢出了一些男學生的基本信息和成績信息,若是下次還想獲得這些信息,咱們就不得不把這個又臭又長的查詢語句再敲一遍,因此MySQL
提供了視圖
(英文名VIEW
)來幫助咱們用很容易的方式去複用這些查詢語句。sql
一個視圖
能夠理解爲一個查詢語句的別名,建立視圖
的語句以下:數據庫
CREATE VIEW 視圖名 AS 查詢語句
複製代碼
好比咱們想根據上邊那個又臭又長的查詢語句來建立一個視圖
能夠這麼寫:bash
mysql> CREATE VIEW male_student_info AS SELECT s1.number, s1.name, s1.major, s2.subject, s2.score FROM student_info AS s1 INNER JOIN student_score AS s2 WHERE s1.number = s2.number AND s1.sex = '男';
Query OK, 0 rows affected (0.02 sec)
mysql>
複製代碼
這樣,這個名稱爲male_student_info
的視圖就表明了那一串又臭又長的查詢語句了。服務器
視圖
也被稱爲虛擬表
,由於咱們能夠對視圖
進行一些相似表的增刪改查操做,只不過咱們對視圖的相關操做都會被映射到那個又臭又長的查詢語句對應的底層的表上。那一串又臭又長的查詢語句的查詢列表能夠被看成視圖
的虛擬列
,比方說male_student_info
這個視圖對應的查詢語句中的查詢列表是number
、name
、major
、subject
、score
,它們也是male_student_info
視圖的虛擬列
。函數
好比咱們可使用日常的查詢語句從視圖
中查詢咱們須要的信息能夠這麼寫:學習
mysql> SELECT * FROM male_student_info;
+----------+-----------+--------------------------+-----------------------------+-------+
| number | name | major | subject | score |
+----------+-----------+--------------------------+-----------------------------+-------+
| 20180101 | 杜子騰 | 計算機科學與工程 | 母豬的產後護理 | 78 |
| 20180101 | 杜子騰 | 計算機科學與工程 | 論薩達姆的戰爭準備 | 88 |
| 20180103 | 範統 | 軟件工程 | 母豬的產後護理 | 59 |
| 20180103 | 範統 | 軟件工程 | 論薩達姆的戰爭準備 | 61 |
+----------+-----------+--------------------------+-----------------------------+-------+
4 rows in set (0.00 sec)
mysql>
複製代碼
這裏咱們的查詢列表是*
,這也就意味着male_student_info
所表明的查詢語句的結果集將做爲整個查詢的結果集返回。從這個例子中咱們也能夠看到,咱們再也不須要使用那句又臭又長的鏈接查詢語句了,只須要從它對應的視圖
中查詢便可。優化
除此以外,咱們在真實表中使用的那些查詢語句均可以被用到視圖
這個虛擬表中,比方說這個查詢語句:ui
mysql> SELECT subject, AVG(score) FROM male_student_info WHERE score > 60 GROUP BY subject HAVING AVG(score) > 75 LIMIT 1;
+-----------------------+------------+
| subject | AVG(score) |
+-----------------------+------------+
| 母豬的產後護理 | 78.0000 |
+-----------------------+------------+
1 row in set (0.00 sec)
mysql>
複製代碼
咱們再次強調一遍,視圖
其實就是某個查詢的別名,而不是某個查詢的結果集,換句話說就是,建立視圖的時候並不會把那個又臭又長的查詢語句的結果集維護在硬盤或者內存裏!在對視圖進行查詢時,MySQL
服務器將會幫助咱們把對視圖的查詢語句轉換爲對底層表的查詢語句而後再執行,因此上邊這個查詢其實會被轉換成下邊這個查詢語句去執行:
SELECT subject, AVG(score) FROM student_info AS s1 INNER JOIN student_score AS s2 WHERE s1.number = s2.number AND s1.sex = '男' AND score > 60 GROUP BY subject HAVING AVG(score) > 75;
複製代碼
只不過這個轉換的過程咱們並不能看到,因此主觀上認爲硬盤或內存裏真的維護了一個視圖對應的表而已~ 更復雜的一些查詢語句,好比子查詢、鏈接查詢什麼的,均可以被用到視圖上,咱們這裏就不舉例子了。
有一點比較有趣的是,在查詢時,視圖能夠和表一塊兒使用,包括子查詢和鏈接查詢,好比這樣:
mysql> SELECT * FROM male_student_info WHERE number IN (SELECT number FROM student_info WHERE major = '計算機科學與工程');
+----------+-----------+--------------------------+-----------------------------+-------+
| number | name | major | subject | score |
+----------+-----------+--------------------------+-----------------------------+-------+
| 20180101 | 杜子騰 | 計算機科學與工程 | 母豬的產後護理 | 78 |
| 20180101 | 杜子騰 | 計算機科學與工程 | 論薩達姆的戰爭準備 | 88 |
+----------+-----------+--------------------------+-----------------------------+-------+
2 rows in set (0.00 sec)
mysql>
複製代碼
因此在使用層面,咱們徹底能夠把視圖
看成一個表去使用,可是它的實現原理倒是在執行語句時轉換爲對底層表的操做。使用視圖的好處也是顯而易見的,咱們能夠複用某個查詢語句,從而簡化了查詢操做,避免了每次查詢時都要寫一遍又臭又長的語句;對視圖的操做更加直觀,而不用考慮它底層的查詢細節。
咱們前邊說視圖是某個查詢語句的別名,其實這個查詢語句不只能夠從普通的表中查詢數據,也能夠從另外一個視圖中查詢數據,只要是個合法的查詢語句就行了。比方說咱們利用male_student_info
視圖來建立另外一個新視圖能夠這麼寫:
mysql> CREATE VIEW by_view AS SELECT number, name, score FROM male_student_info;
Query OK, 0 rows affected (0.02 sec)
mysql>
複製代碼
咱們查詢一下這個從另外一個視圖中生成的視圖:
mysql> SELECT * FROM by_view;
+----------+-----------+-------+
| number | name | score |
+----------+-----------+-------+
| 20180101 | 杜子騰 | 78 |
| 20180101 | 杜子騰 | 88 |
| 20180103 | 範統 | 59 |
| 20180103 | 範統 | 61 |
+----------+-----------+-------+
4 rows in set (0.00 sec)
mysql>
複製代碼
這種利用其餘的視圖來生成的新視圖也被稱爲嵌套視圖
,在對某個嵌套視圖
執行查詢時,查詢語句會先被轉換成對它依賴的視圖的查詢,再轉換成對底層表的查詢。
咱們前邊說過視圖
的虛擬列
實際上是這個視圖對應的查詢語句的查詢列表,咱們也能夠在建立列表的時候爲這些虛擬列
自定義列名,這些自定義列名寫到視圖名後邊,用逗號,
分隔就行了,不過須要注意的是,自定義列名必定要和查詢列表中的查詢對象一一對應。好比咱們新建立一個自定義列名的視圖:
mysql> CREATE VIEW student_info_view(no, n, m) AS SELECT number, name, major FROM student_info;
Query OK, 0 rows affected (0.02 sec)
mysql>
複製代碼
咱們的自定義列名列表是no, n, m
,分別對應查詢列表中的number, name, major
。有了自定義列名以後,咱們以後對視圖的查詢語句都要基於這些自定義列名,好比咱們能夠這麼查詢:
mysql> SELECT no, n, m FROM student_info_view;
+----------+-----------+--------------------------+
| no | n | m |
+----------+-----------+--------------------------+
| 20180101 | 杜子騰 | 計算機科學與工程 |
| 20180102 | 杜琦燕 | 計算機科學與工程 |
| 20180103 | 範統 | 軟件工程 |
| 20180104 | 史珍香 | 軟件工程 |
| 20180105 | 範劍 | 飛行器設計 |
| 20180106 | 朱逸羣 | 電子信息 |
+----------+-----------+--------------------------+
6 rows in set (0.00 sec)
mysql>
複製代碼
若是仍舊使用與視圖對應的查詢語句的查詢列表中的列名就會報錯,好比這樣:
mysql> SELECT number, name, major FROM student_info_view;
ERROR 1054 (42S22): Unknown column 'number' in 'field list'
mysql>
複製代碼
咱們想查看當前數據庫中有哪些視圖的話,其實和查看有哪些表的命令是同樣的:
mysql> SHOW TABLES;
+---------------------+
| Tables_in_xiaohaizi |
+---------------------+
| by_view |
| first_table |
| male_student_info |
| second_table |
| student_info |
| student_info_view |
| student_score |
| t |
| t1 |
| t2 |
| t3 |
| zero_table |
+---------------------+
12 rows in set (0.00 sec)
mysql>
複製代碼
能夠看到,咱們建立的幾個視圖,包括by_view
、male_student_info
、student_info_view
就都顯示出來了。須要注意的是,由於視圖是一張虛擬表
,因此新建立的視圖的名稱不能和當前數據庫中的其餘視圖或者表的名稱衝突!
由於視圖是一張虛擬表
,因此用來查看錶結構的語句均可以用來查看視圖的結構,不過咱們常用的查看視圖定義語句是這個:
SHOW CREATE VIEW 視圖名
複製代碼
咱們來查看一下student_info_view
視圖的定義:
mysql> SHOW CREATE VIEW student_info_view\G
*************************** 1. row ***************************
View: student_info_view
Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `student_info_view` AS select `student_info`.`number` AS `no`,`student_info`.`name` AS `n`,`student_info`.`major` AS `m` from `student_info`
character_set_client: utf8
collation_connection: utf8_general_ci
1 row in set (0.00 sec)
mysql>
複製代碼
若是某個視圖咱們不想要了,可使用這個語句來刪除掉它:
DROP VIEW 視圖名
複製代碼
好比咱們把by_view
視圖刪掉能夠這麼寫:
mysql> DROP VIEW by_view;
Query OK, 0 rows affected (0.00 sec)
mysql>
複製代碼
而後再查看當前數據庫中的表:
mysql> SHOW TABLES;
+---------------------+
| Tables_in_xiaohaizi |
+---------------------+
| first_table |
| male_student_info |
| second_table |
| student_info |
| student_info_view |
| student_score |
| t |
| t1 |
| t2 |
| t3 |
| zero_table |
+---------------------+
11 rows in set (0.00 sec)
mysql>
複製代碼
這個視圖就不見了!
咱們前邊進行的都是對視圖的查詢操做,其實也能夠對視圖進行更新,也就是在視圖上執行INSERT
、DELETE
、UPDATE
語句。對視圖執行更新語句的本質上是對該視圖對應的底層表進行更新。比方說視圖student_info_view
的底層表是student_info
,因此若是咱們對student_info_view
執行更新語句就至關於對student_info
表進行更新,比方說咱們執行這個語句:
mysql> UPDATE student_info_view SET n = '111' WHERE no = 20180101;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql>
複製代碼
咱們再到student_info
表中看一下這個學生的名稱是否被改了:
mysql> SELECT name FROM student_info WHERE number = 20180101;
+------+
| name |
+------+
| 111 |
+------+
1 row in set (0.00 sec)
mysql>
複製代碼
名稱的確被更改爲功了!
不過並非能夠在全部的視圖上執行更新語句的,在生成視圖的時候使用了下邊這些語句的都不能進行更新:
雖然有這麼多限制,可是須要咱們注意的是,通常狀況下,咱們只在視圖上執行查詢操做而不進行更新操做!這裏介紹對視圖的更新只是爲了語法的完整性,並非建議你們在實際使用過程當中使用對視圖的更新功能。
本系列專欄都是MySQL入門知識,想看進階知識能夠到小冊中查看:《MySQL是怎樣運行的:從根兒上理解MySQL》的連接 。小冊的內容主要是從小白的角度出發,用比較通俗的語言講解關於MySQL進階的一些核心概念,好比記錄、索引、頁面、表空間、查詢優化、事務和鎖等,總共的字數大約是三四十萬字,配有上百幅原創插圖。主要是想下降普通程序員學習MySQL進階的難度,讓學習曲線更平滑一點~