史上最簡單MySQL教程詳解(進階篇)之視圖
爲什麼要用視圖
在設計數據庫的過程中,爲了防止數據的冗長性(即:同樣的數據在多個表中重複出現的情況),就需要去遵守我們在前面的文章史上最簡單MySQL教程詳解(基礎篇)之數據庫設計範式及應用舉例中介紹的有關數據庫設計的一些規範,這樣雖然讓表的設計更加合理,但是我們可能會使用到多表連接等方式查詢,就會增加SQL語句的複雜度,從而增大服務器的負擔,降低查詢效率,增加響應時間。
例如:我們有如下幾個字段(學號,學生姓名,電話號碼,家庭住址,課程編號,課程名字,授課教師…),請設計表結構來實現如下需求:能夠查詢出所有的學號,電話號碼,及其選則的所有課程名字和授課教師。
可能第一反應是:【student】表爲(學號,學生姓名,電話號碼,家庭住址)和【course】表(學號,電話號碼,所選的課程編號、課程名字、授課教師),因爲這樣能夠快速的查詢出我們所需要的數據,但是,假設某個學生的電話號碼變化了呢?是不是又需要更改很多的表?而且這樣冗雜的數據,根據設計規範也是不允許的。
所以,爲了防止上述情況的發生,我們可以設計成這樣【student】表(學號,學生姓名,電話號碼,家庭住址),【course】表(課程編號,課程名字,授課教師),【choose】(學號,課程編號)。
當我們像這樣設計數據表時,就遵循了數據庫的設計規範,但同時我們在查詢的時候就需要聯合【student】和【course】表才能查詢。所以,當這樣我們需要一次性查詢多個表的數據,但是爲了表的規範,又沒有辦法將需要查詢的數據保存在一個表中的時候,就會使用到視圖(View)。
視圖的本質
視圖(View)的本質是將我們的Select語句的檢索結果用表的形式保存下來,所以有時候視圖又稱爲假表或者僞表。這是因爲視圖本身其實是不包含數據的,僅僅從對象表中動態地抽取數據,並將數據組織在一起,看上去和我們平時使用的表一樣。
視圖的作用
(1)可以只公開表中的特定行或者列:通過限制用戶對實際表的SELECT操作權限,而僅賦予用戶對相應視圖的SELECT操作權限,來達到限制用戶只讀取表中特定行或列的目的。(因爲一般視圖在使用過程中,抽取的正是表中的一些特定行或列,而非整張表)
(2)簡化SQL查詢的複雜度,增強可讀性:使用了視圖後,視圖就已經成爲了檢索後的假想表,省去了編寫複雜SQL查詢語句的過程,直接查詢視圖中的內容即可。當連接或者子查詢發生改變時,只需要修改視圖的定義,就可以大大減少修改的範圍。
(3)可以限制可插入或更新的範圍:在定義視圖時加入【WITH CHECK OPTION】命令後,使用【INSERT】或者【UPDATE】命令操作數據時,數據庫都會進行強制檢查,不符合視圖定義的數據將被限制操作(即:操作後的數據是否還在視圖中,如果操作後不存在,則禁止操作)。如果沒有加入WITH CHECK OPTION】,則不會進行限制。
如何使用視圖
我們先創建下面三個表:
1.student表
列名 | 解釋 |
---|---|
studentId | 學號 |
studentName | 名字 |
studentPhone | 電話 |
studentAddress | 地址 |
CREATE TABLE `student` (
`studentId` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`studentName` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`studentPhone` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`studentAddress` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`studentId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2.course表
列名 | 說明 |
---|---|
courseId | 課程Id |
courseName | 課程名 |
courseTeacher | 授課教師 |
CREATE TABLE `course` (
`courseId` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`courseName` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`courseTeacher` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`courseId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
3.choose
列名 | 說明 |
---|---|
courseId | 課程ID |
studentId | 學號 |
CREATE TABLE `chooese` (
`courseId` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`studentId` varchar(255) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
然後,我們隨便填入幾種數據,我們按照以往的方法,我們執行的SQL查詢語句爲:
mysql> Select stu.studentName AS name,
stu.studentPhone AS phone ,
co.courseName AS coname ,
co.courseTeacher AS teacher
FROM (
(
choose AS choo INNER JOIN student AS stu ON choo.studentId = stu.studentId)
INNER JOIN course AS co ON co.courseId = choo.courseId);
+--------+-------+--------+---------+
| name | phone | coname | teacher |
+--------+-------+--------+---------+
| 張三 | 139 | 英語 | 張老師 |
| 李四 | 137 | 英語 | 張老師 |
| 王五 | 135 | 數學 | 李老師 |
| 路人乙 | 118 | 語文 | 王老師 |
| 李四 | 137 | 語文 | 王老師 |
+--------+-------+--------+---------+
5 rows in set
創建視圖
創建視圖使用的是【CREATE VIEW】命令,具體語法如下:
CREATE VIEW 視圖名(列名1,列名2...)AS 查詢語句 [WITH CHECK OPTION];
例如,我們給剛纔創建的表創建視圖:
CREATE VIEW result(name,phone,coname,teacher) AS
Select stu.studentName
AS name,stu.studentPhone AS phone ,
co.courseName AS coname ,
co.courseTeacher AS teacher FROM (
(
choose AS choo INNER JOIN student AS stu ON choo.studentId = stu.studentId
)INNER JOIN course AS co ON co.courseId = choo.courseId ) with check option;
Query OK, 0 rows affected
注意事項:創建視圖時,SELECT命令有如下限制
不能包含系統變量/用戶變量的參照;
TEMPORARY類型的表
FROM語句後的子查詢
使用【SHOW TABLES】即可查看我們剛纔創建的視圖
mysql> show tables;
+-----------------+
| Tables_in_test1 |
+-----------------+
| choose |
| course |
| result |
| student |
+-----------------+
4 rows in set
注意事項:
因爲我們在使用【SHOW】命令查看的時候就會發現,視圖和實際的表都是會顯示的,這樣就不容易分辨出究竟是視圖還是實際的表,所以,建議對於視圖來說,建議以v_視圖名的方式來命名,這樣就很容易識別。
修改視圖
修改已經創建好的視圖,使用【REPLACE】命令,具體語法如下:
CREATE OR REPLACE VIEW 視圖名 AS SELECT [...] FROM [...];
例如:
CREATE OR REPLACE VIEW v_result(name,phone,coname,teacher) AS
Select stu.studentName
AS name,stu.studentPhone AS phone ,
co.courseName AS coname ,
co.courseTeacher AS teacher FROM (
(
choose AS choo INNER JOIN student AS stu ON choo.studentId = stu.studentId
)INNER JOIN course AS co ON co.courseId = choo.courseId ) with check option;
刪除視圖
刪除已經創建的視圖使用【DROP】命令,語法如下:
DROP VIEW 視圖名;
例如:
mysql> DROP VIEW result; //刪除之前創建的result表
Query OK, 0 rows affected
mysql> SHOW TABLES; //查看是否刪除成功
+-----------------+
| Tables_in_test1 |
+-----------------+
| choose |
| course |
| student |
| v_result |
+-----------------+
4 rows in set
查看視圖
查看視圖所有列的信息和平時我們使用的表一樣,使用【SHOW】命令,具體語法如下:
SHOW FIELDS FROM 視圖名;
例如:
mysql> SHOW FIELDS FROM v_result;
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| name | varchar(255) | NO | | NULL | |
| phone | varchar(255) | NO | | NULL | |
| coname | varchar(255) | NO | | NULL | |
| teacher | varchar(255) | NO | | NULL | |
+---------+--------------+------+-----+---------+-------+
4 rows in set
使用視圖檢索
使用視圖檢索的時候,和使用普通表一樣,使用【SELECT】語句,例如:
mysql> SELECT * FROM v_result WHERE name = "李四";
+------+-------+--------+---------+
| name | phone | coname | teacher |
+------+-------+--------+---------+
| 李四 | 137 | 英語 | 張老師 |
| 李四 | 137 | 語文 | 王老師 |
+------+-------+--------+---------+
2 rows in set
變更視圖數據
當我們對於視圖中的數據進行插入、更新、刪除等操作時,和實際的表方式相同,都使用的【INSERT】、【UPDATE】、【DELETE】語句。例如:
mysql> UPDATE v_result SET phone = '140' WHERE name = '張三'; //將張三的電話修改爲‘140’
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM v_result ; //視圖中修改成功
+--------+-------+--------+---------+
| name | phone | coname | teacher |
+--------+-------+--------+---------+
| 張三 | 140 | 英語 | 張老師 |
| 李四 | 137 | 英語 | 張老師 |
| 王五 | 135 | 數學 | 李老師 |
| 路人乙 | 118 | 語文 | 王老師 |
| 李四 | 137 | 語文 | 王老師 |
+--------+-------+--------+---------+
5 rows in set
mysql> SELECT * FROM student; //實際表中的數據也修改成功
+-----------+-------------+--------------+----------------+
| studentId | studentName | studentPhone | studentAddress |
+-----------+-------------+--------------+----------------+
| 1 | 張三 | 140 | 重慶 |
| 2 | 李四 | 137 | 北京 |
| 3 | 王五 | 135 | 上海 |
| 4 | 路人甲 | 132 | 廣州 |
| 5 | 路人乙 | 118 | 深圳 |
+-----------+-------------+--------------+----------------+
5 rows in set
注意事項:在以下幾種條件下不能進行插入/更新/刪除操作。
視圖的列中含有統計函數的情況下;
視圖定義時使用了GROUP BY/HAVING語句,DISTINCT語句、UNION語句的情況下;
視圖定義時使用了子查詢的情況下;
進行跨越多個表進行數據的變更操作;
WITH CHECK OPTION 分析
前面我們介紹過,【 WITH CHECK OPTION】可以用於限制可插入或更新的範圍。如果我們在創建視圖的時候使用了【 WITH CHECK OPTION】語句,那麼當我們執行插入語句時,就會報錯:【Can not modify more than one base table through a join view】,不能修改超過一個基礎表以上的情況。例如:
mysql> INSERT INTO v_result(name,phone,coname,teacher) VALUES ('趙六','130','歷史','趙老師');
1393 - Can not modify more than one base table through a join view 'test1.v_result'
所以爲了避免不必要的混亂和不可預知的BUG,建議在創建視圖時加上【 WITH CHECK OPTION】語句。
總結
視圖是一個非常方便的功能,但是對於性能來說並非是一個最好的選擇。視圖可以簡化複雜的SQL查詢語句,但是並不能簡化內部處理。另外,視圖還可以在視圖的基礎上再次定義,但是這必將導致數據庫性能的下降,所以還是酌情使用。
參考文獻:
《MySQ高效編程》