概述
很多時候,我們會有一些很復雜的數據庫操作,比如整合用戶的行為數據,那這些數據可能包含用戶的餐飲、生活日用、充值消費、交通出行、通訊物流、交通出行、醫療保健、住房物業、運動健康...
基於此,我們可能要去關聯很多的用戶行為信息表,寫一大堆的合並、統計,以及條件過濾的腳本,來輸出最終的二維表,這才是用戶真正需要的數據。如果把這些復雜的腳本寫在業務程序中不是很合理,那有什么辦法把
這些腳本細節隱藏,只顯示只顯示簡潔的結果呢,那就要用到視圖了。
視圖是由數據庫中的一個表或多個表導出的虛擬表,是一種虛擬存在的表,方便用戶對數據的操作。
概念
視圖是在mysql5之后出現的,是一種虛擬表,行和列的數據來自於定義視圖時使用的一些表中,視圖的數據是在使用視圖的時候動態生成的,視圖只保存了sql的邏輯,不保存查詢的結果。
使用場景
多個業務場景使用到相同的查詢結果,並且該查詢結果比較復雜的時候,我們可以使用視圖來隱藏復雜的實現細節。
視圖和表比較
語法 | 實際中是否占用物理空間 | 使用 | |
---|---|---|---|
視圖 | create view | 否,僅保存sql的邏輯 | 增刪改查,實際上我們只使用查詢 |
表 | create table | 是,保存了數據 | 增刪改查 |
視圖的作用
對其中所引用的基礎表來說,視圖的作用類似於篩選。定義視圖的篩選可以來自當前或其他數據庫的一個或多個表,或者其他視圖。通過視圖進行查詢沒有任何限制,通過它們進行數據修改時的限制也很少。視圖的作用歸納為如下幾點。
1、簡單性
看到的就是需要的。視圖不僅可以簡化用戶對數據的理解,也可以簡化他們的操作。那些被經常使用的查詢可以被定義為視圖,從而使得用戶不必為以后的操作每次指定查詢的條件。
經常需要聯合查詢的內容也可以指定為視圖,這樣就不需要每次都寫大量的聯表腳本。
2、安全性
視圖的安全性可以防止未授權用戶查看特定的行或列,使有權限用戶只能看到表中特定行的方法,比如把只有某部分數據查詢視圖授權給某個用戶。
3、邏輯數據獨立性
視圖可以使應用程序和數據庫表在一定程度上獨立。如果沒有視圖,程序一定是建立在表上的。有了視圖之后,程序可以建立在視圖之上,從而程序與數據庫表被視圖分割開來。視圖可以在以下幾個方面使程序與數據獨立。
(1)如果應用建立在數據庫表上,當數據庫表發生變化時,可以在表上建立視圖,通過視圖屏蔽表的變化,從而使應用程序可以不動。
(2)如果應用建立在數據庫表上,當應用發生變化時,可以在表上建立視圖,通過視圖屏蔽應用的變化,從而使數據庫表不動。
(3)如果應用建立在視圖上,當數據庫表發生變化時,可以在表上修改視圖,通過視圖屏蔽表的變化,從而使應用程序可以不動。
(4)如果應用建立在視圖上,當應用發生變化時,可以在表上修改視圖,通過視圖屏蔽應用的變化,從而使數據庫可以不動。
數據准備
表名 | 描述 |
---|---|
departments | 部門表 |
employees | 員工信息表 |
jobs | 職位信息表 |
locations | 位置表(部門表中會用到) |
job_grades | 薪資等級表 |
創建視圖
MySQL中,創建視圖是通過CREATE VIEW語句實現的。
語法
1 CREATE [OR REPLACE] [ALGORITHM={UNDEFINED|MERGE|TEMPTABLE}] 2 VIEW ViewName[(ColumnList)] 3 AS SELECT ... 4 [WITH [CASCADED|LOCAL] CHECK OPTION];
參數說明:
(1)ALGORITHM:可選項,表示視圖選擇的算法。
(2)ViewName 視圖名:表示要創建的視圖名稱。
(3)ColumnList 屬性清單:可選項,指定視圖中各個屬性的名詞,默認情況下與SELECT語句中的查詢的屬性相同。
(4)SELECT語句:表示一個完整的查詢語句,將查詢記錄導入視圖中。
(5)WITH CHECK OPTION:可選項,表示更新視圖時要保證在該視圖的權限范圍之內。
視圖的使用步驟
(1)創建視圖
(2)對視圖執行查詢操作
對單表的操作
查詢出訂單表中,單筆訂單額度超過100元的數據,下面依次展示創建視圖和查詢視圖。
1 mysql> select * from t_order; 2 +---------+-----+-------+--------+---------------------+------+ 3 | orderid | uid | uname | amount | time | year | 4 +---------+-----+-------+--------+---------------------+------+ 5 | 20 | 1 | brand | 91.23 | 2018-08-20 17:22:21 | 2018 | 6 | 21 | 1 | brand | 87.54 | 2019-07-16 09:21:30 | 2019 | 7 | 22 | 1 | brand | 166.88 | 2019-04-04 12:23:55 | 2019 | 8 | 23 | 2 | helyn | 93.73 | 2019-09-15 10:11:11 | 2019 | 9 | 24 | 2 | helyn | 102.32 | 2019-01-08 17:33:25 | 2019 | 10 | 25 | 2 | helyn | 106.06 | 2019-12-24 12:25:25 | 2019 | 11 | 26 | 2 | helyn | 73.42 | 2020-04-03 17:16:23 | 2020 | 12 | 27 | 3 | sol | 55.55 | 2019-08-05 19:16:23 | 2019 | 13 | 28 | 3 | sol | 69.96 | 2020-09-16 19:23:16 | 2020 | 14 | 29 | 4 | weng | 199.99 | 2020-06-08 19:55:06 | 2020 | 15 +---------+-----+-------+--------+---------------------+------+ 16 10 rows in set 17 18 mysql> create view view1 19 -> as select * from t_order where amount >100; 20 Query OK, 0 rows affected 21 22 mysql> select * from view1; 23 +---------+-----+-------+--------+---------------------+------+ 24 | orderid | uid | uname | amount | time | year | 25 +---------+-----+-------+--------+---------------------+------+ 26 | 22 | 1 | brand | 166.88 | 2019-04-04 12:23:55 | 2019 | 27 | 24 | 2 | helyn | 102.32 | 2019-01-08 17:33:25 | 2019 | 28 | 25 | 2 | helyn | 106.06 | 2019-12-24 12:25:25 | 2019 | 29 | 29 | 4 | weng | 199.99 | 2020-06-08 19:55:06 | 2020 | 30 +---------+-----+-------+--------+---------------------+------+ 31 4 rows in set 32 33 mysql> select * from view1 where year = 2019; 34 +---------+-----+-------+--------+---------------------+------+ 35 | orderid | uid | uname | amount | time | year | 36 +---------+-----+-------+--------+---------------------+------+ 37 | 22 | 1 | brand | 166.88 | 2019-04-04 12:23:55 | 2019 | 38 | 24 | 2 | helyn | 102.32 | 2019-01-08 17:33:25 | 2019 | 39 | 25 | 2 | helyn | 106.06 | 2019-12-24 12:25:25 | 2019 | 40 +---------+-----+-------+--------+---------------------+------+ 41 3 rows in set
上面我們創建了一個視圖:view1,我們需要看某個條件下的信息時,不用關心這個視圖內部是什么樣的,只需要查詢視圖就可以了,sql簡單很多。
對多表的操作
有兩個表:學生、班級,數據基數如下,需要創建一個視圖,統計每個班級的人數和平均成績和總成績。
1 mysql> select * from classes; 2 +---------+-----------+ 3 | classid | classname | 4 +---------+-----------+ 5 | 1 | 初三一班 | 6 | 2 | 初三二班 | 7 | 3 | 初三三班 | 8 +---------+-----------+ 9 3 rows in set 10 11 mysql> select * from students; 12 +-----------+-------------+-------+---------+ 13 | studentid | studentname | score | classid | 14 +-----------+-------------+-------+---------+ 15 | 1 | brand | 97.5 | 1 | 16 | 2 | helen | 96.5 | 1 | 17 | 3 | lyn | 96 | 1 | 18 | 4 | sol | 97 | 1 | 19 | 7 | b1 | 81 | 2 | 20 | 8 | b2 | 82 | 2 | 21 | 13 | c1 | 71 | 3 | 22 | 14 | c2 | 72.5 | 3 | 23 | 19 | lala | 51 | 0 | 24 +-----------+-------------+-------+---------+ 25 9 rows in set
1 mysql> create view view2 as select a.classname as '班級名稱',count(b.studentid) as '總人數',sum(b.score) as '總分',avg(b.score) as '平均分' 2 from classes a inner join students b on a.classid = b.classid 3 group by a.classid,a.classname; 4 Query OK, 0 rows affected 5 6 mysql> select * from view2; 7 +----------+--------+--------+-----------+ 8 | 班級名稱 | 總人數 | 總分 | 平均分 | 9 +----------+--------+--------+-----------+ 10 | 初三一班 | 4 | 387.00 | 96.750000 | 11 | 初三二班 | 2 | 163.00 | 81.500000 | 12 | 初三三班 | 2 | 143.50 | 71.750000 | 13 +----------+--------+--------+-----------+ 14 3 rows in set
查詢視圖結構
使用 desc viewname 語法查看視圖的結構
1 mysql> desc view2; 2 +----------+---------------+------+-----+---------+-------+ 3 | Field | Type | Null | Key | Default | Extra | 4 +----------+---------------+------+-----+---------+-------+ 5 | 班級名稱 | varchar(30) | YES | | NULL | | 6 | 總人數 | bigint(21) | NO | | 0 | | 7 | 總分 | decimal(32,2) | YES | | NULL | | 8 | 平均分 | decimal(14,6) | YES | | NULL | | 9 +----------+---------------+------+-----+---------+-------+ 10 4 rows in set
使用show create view語法查看視圖創建信息
1 mysql> show create view view2; 2 +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+ 3 | View | Create View | character_set_client | collation_connection | 4 +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+ 5 | view2 | CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `view2` AS select `a`.`classname` AS `班級名稱`,count(`b`.`studentid`) AS `總人數`,sum(`b`.`score`) AS `總分`,avg(`b`.`score`) AS `平均分` from (`classes` `a` join `students` `b` on((`a`.`classid` = `b`.`classid`))) group by `a`.`classid`,`a`.`classname` | utf8 | utf8_general_ci | 6 +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+ 7 1 row in set
修改視圖
修改視圖是指修改數據庫中已存在的表的定義。當基本表的某些字段發生改變時,可以通過修改視圖來保持視圖和基本表之間一致。MySQL中通過CREATE OR REPLACE VIEW語句和ALTER VIEW語句來修改視圖。
create or replace方式
當視圖存在時,修改,不存在時,創建新的視圖。
1 mysql> create or replace view view2 as select a.classname as '班級名稱',count(b.studentid) as '總人數',sum(b.score) as '總分',avg(b.score) as '平均分' 2 from classes a inner join students b on a.classid = b.classid 3 group by a.classid,a.classname; 4 Query OK, 0 rows affected 5 6 mysql> select * from view2; 7 +----------+--------+--------+-----------+ 8 | 班級名稱 | 總人數 | 總分 | 平均分 | 9 +----------+--------+--------+-----------+ 10 | 初三一班 | 4 | 387.00 | 96.750000 | 11 | 初三二班 | 2 | 163.00 | 81.500000 | 12 | 初三三班 | 2 | 143.50 | 71.750000 | 13 +----------+--------+--------+-----------+ 14 3 rows in set
alter方式
1 mysql> alter view view2 as select a.classname as '班級名稱',count(b.studentid) as '總人數',sum(b.score) as '總分',avg(b.score) as '平均分' 2 from classes a inner join students b on a.classid = b.classid 3 group by a.classid,a.classname; 4 Query OK, 0 rows affected 5 6 mysql> select * from view2; 7 +----------+--------+--------+-----------+ 8 | 班級名稱 | 總人數 | 總分 | 平均分 | 9 +----------+--------+--------+-----------+ 10 | 初三一班 | 4 | 387.00 | 96.750000 | 11 | 初三二班 | 2 | 163.00 | 81.500000 | 12 | 初三三班 | 2 | 143.50 | 71.750000 | 13 +----------+--------+--------+-----------+ 14 3 rows in set
刪除視圖
刪除視圖是指刪除數據庫中已存在的視圖。刪除視圖時,只能刪除視圖的定義,不會刪除數據。MySQL中,使用DROP VIEW語句來刪除視圖。但是,用戶必須擁有DROP權限。
語法
1 DROP VIEW IF EXISTS vname1[,vname2][,vname3];
可以刪除多個視圖,多個視圖名稱使用都好隔開。
1 mysql> DROP VIEW IF EXISTS view1,view2; 2 Query OK, 0 rows affected
更新視圖數據
即更改視圖中的數據,而不是更改視圖中的sql邏輯。當對視圖進行更新后,也會對原始表的數據進行更新。
為了防止對原始表的數據產生更新,可以為視圖添加只讀權限,只允許讀視圖,不允許對視圖進行更新。一般比較少這么操作:
1 mysql> create view view1 as select * from classes; 2 Query OK, 0 rows affected 3 4 mysql> select * from view1; 5 +---------+-----------+ 6 | classid | classname | 7 +---------+-----------+ 8 | 1 | 初三一班 | 9 | 2 | 初三二班 | 10 | 3 | 初三三班 | 11 +---------+-----------+ 12 3 rows in set 13 14 mysql> insert into view1 values(4,'出三四班'); 15 Query OK, 1 row affected 16 17 mysql> update view1 set classname='初三四班' where classid=4; 18 Query OK, 1 row affected 19 Rows matched: 1 Changed: 1 Warnings: 0 20 21 mysql> select * from view1; 22 +---------+-----------+ 23 | classid | classname | 24 +---------+-----------+ 25 | 1 | 初三一班 | 26 | 2 | 初三二班 | 27 | 3 | 初三三班 | 28 | 4 | 初三四班 | 29 +---------+-----------+ 30 4 rows in set
視圖的更新我們一般不使用,為了保護視圖的某部分區間的數據不被修改,一般會使用WITH CHECK OPTION約束 ,甚至設置為只讀視圖。
with check option
視圖只操作它能夠查詢出來的數據,對於查詢不出的數據,即使基表中存在數據,也不可以通過視圖來操作。針對這方面的限制有 with check option 表達式進行操作。他對delete、insert、update分別有如下約束:
關鍵字類型 | 描述 |
---|---|
update | 有with check option,要保證update后,數據能被視圖查詢出來 |
delete | 有無with check option都一樣 |
insert | 有with check option,要保證insert后,數據要被視圖查詢出來 |
下面創建兩個同樣結果的視圖,一個帶with check option,一個不帶。
1 mysql> create view v as select * from t_order where amount>0; 2 Query OK, 0 rows affected 3 4 mysql> create view v_option as select * from t_order where amount>0 with check option; 5 Query OK, 0 rows affected 6 7 mysql> select * from t_order; 8 +---------+---------+---------+-------+ 9 | orderid | account | amount | goods | 10 +---------+---------+---------+-------+ 11 | 8 | brand | 52.2 | 2 | 12 | 9 | hen | 1752.02 | 7 | 13 | 10 | helyn | 88.5 | 4 | 14 | 11 | sol | 1007.9 | 11 | 15 | 12 | diny | 12 | 1 | 16 | 13 | weng | 52.2 | 5 | 17 | 14 | sally | 99.71 | 9 | 18 | 15 | brand1 | -99.99 | 6 | 19 +---------+---------+---------+-------+ 20 8 rows in set
原表有8條數據,因為條件限制,視圖無法讀取到最后一條數據,即只有前7條數據。那根據上面的規則,使用v_option視圖進行修改,修改他查詢范圍之外的數據應該是不允許的,我們來試試:
1 mysql> update v_option set amount=-8 where orderid=12; 2 1369 - CHECK OPTION failed 'test.v_option'
amout = -8,改完后數據會跑到視圖可查詢范圍之外,所以被限制了。使用不限制的視圖就可以了,如下:
1 mysql> update v set amount=-8 where orderid=12; 2 Query OK, 1 row affected 3 Rows matched: 1 Changed: 1 Warnings: 0 4 5 mysql> select * from t_order; 6 +---------+---------+---------+-------+ 7 | orderid | account | amount | goods | 8 +---------+---------+---------+-------+ 9 | 8 | brand | 52.2 | 2 | 10 | 9 | hen | 1752.02 | 7 | 11 | 10 | helyn | 88.5 | 4 | 12 | 11 | sol | 1007.9 | 11 | 13 | 12 | diny | -8 | 1 | 14 | 13 | weng | 52.2 | 5 | 15 | 14 | sally | 99.71 | 9 | 16 | 15 | brand1 | -99.99 | 6 | 17 +---------+---------+---------+-------+ 18 8 rows in set
同理,delete、insert 也可以驗證下。
總結
-
了解視圖的用途及與表的區別。
-
掌握視圖的創建、使用、修改、刪除。
-
了解視圖的優點:簡單簡潔(隱藏細節,輸出結果)、安全性(用戶只能看到表中特定行的方法)、邏輯數據獨立性。