史上最簡單MySQL教程詳解(進階篇)之視圖

史上最簡單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高效編程》

別忘了關注博主的個人公衆號,有更多精彩內容、資源分享~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章