第8章 索引與視圖數據庫
索引是依賴於數據表或視圖的一種數據庫對象,它保存了針對指定數據表或視圖的鍵值或指針。索引有本身的文件名(即索引文件名),也須要佔用磁盤空間。建立索引的目的爲了提升對數據表或視圖的搜索效率。
對於數據表來講,索引能夠理解爲對一個或多個字段值進行排序的結構,本質上它是指向存儲在表中指定列的數據值的指針。在SQL Server中,索引是用B_樹這種數據結構來構造的,經過索引訪問數據其實是尋找一條從根節點到葉子節點的過程,這個過程通常比直接按順序訪問數據表要高效得多。這是由於經過索引只需少數幾個I/O操做能夠在較短的時間內定位到表中相應的行,而順序訪問則須要從頭至尾逐行比較,在平均意義下使用的時間要多得多。
索引的做用就是提升對數據表的查詢效率,但實際狀況並不老是這樣。若是對數據表建立過多的索引,反而可能使得對數據的查詢效率降低。緣由在於,不但搜索龐大的B_樹須要時間,並且SQL Server對這些B_樹進行維護也可能須要付出巨大的代價和開銷。由於B_樹做爲一種數據結構是存放在數據表之外的地方,須要額外的系統資源,並且當對數據表執行UPDATE、DELETE和INSERT等操做時因須要更改這些B_樹而付出大量的時間代價。所以,索引並非建立得越多就越好。
總之,索引是獨立於數據表的一種數據庫對象,它保存了針對於指定數據表的鍵值和指針。索引文件也須要佔用磁盤空間。建立索引的目的是爲了提升查詢效率。
安全
過多地建立索引反而下降查詢效率,因此如何適當地建立索引,這是問題的關鍵。通常來講,當數據表很大的時候,對於一些用於查詢操做比較頻繁的字段,應該對其建立索引,而對於其餘字段則少建立索引。
設計良好的索引能夠減小磁盤的I/O操做,下降索引對系統資源的消耗,提升SELECT語句執行效率。但因爲執行UPDATE、DELETE或INSERT語句時,須要維護索引,所以可能會下降這些語句的執行效率。
索引的建立是由用戶來完成,而索引的使用則是由SQL Server的查詢優化器來自動實現。須要注意的是,並非全部已建立的索引都會在查詢操做中自動被使用。一個索引被使用與否是由SQL Server的查詢優化器來決定。
數據結構
索引採用的數據結構是B_樹,即在邏輯上索引是一棵B_樹,所以瞭解B_樹有助於對索引原理的理解。
B_樹即平衡樹(Balanced Tree),一棵m階的平衡樹是知足下列性質的樹(在此不考慮空樹):
(1)樹中每一個節點最多有m棵子樹。
(2)根節點除外,全部非葉子節點至少都包含m/2棵子樹。
(3)若根節點不是葉子節點,則根節點至少兩棵子樹。
(4)全部非葉子節點都包含相應的關鍵信息,一個包含k+1棵子樹的非葉節點剛好包含k個關鍵字。
k表示關鍵字的個數。Ki(i=1,2,…,k)爲關鍵字,且Ki < Ki+1。Ai(i=0,2,…,k)爲指向相應子樹根節點的指針,且指針Ai-1所指子樹中全部節點的關鍵字均小於Ki(i=1,2,…,k),而Ai+1所指子樹中全部節點的關鍵字均大於Ki(i=1,2,…,k-1)
(5)全部的葉子節點都出如今同一層次上,而且葉子節點不包含任何關鍵字信息。
例如,圖8.1表示了一棵四階的B_樹。
架構
1. 彙集索引(Clustered Index)
彙集索引的主要特色是,索引順序與數據表中記錄的物理順序相同,每一張數據表只容許擁有一個彙集索引。
彙集索引與數據是「一體」的,其存在是以表中的記錄順序來體現。這是由於在B_樹的葉子節點中存儲的是實際的數據。
爲了形象地介紹彙集索引,考慮表student中對s_no字段建立的彙集索引。其典型的彙集索引結果如圖8.2所示。
由圖8.2能夠看出,彙集索引的索引指針是「不相交」的(這是彙集索引的主要特色),這是由於索引順序與數據記錄的物理順序是一致的。
當對一個表定義主鍵時,彙集索引將自動、隱式被建立。彙集索引通常是在字段值惟一的字段上建立,特別是在主鍵上建立。若是在字段值非惟一的字段上建立彙集索引,那麼SQL Server將對包含此重複字段值的記錄添加4個字節的標識符,以完成對這些包含重複字段值的記錄進行惟一性標識。
彙集索引肯定了表中記錄的物理順序,它適用於使用頻率比較頻繁的查詢、惟一性查詢和範圍查詢等。從SQL語句的角度看,這些查詢主要包括:
使用BETWEEN、>=、>、<=、<等運算符的查詢
使用JOIN子句的查詢
使用GROUP BY子句的查詢
返回大結果集的查詢
在建立彙集索引時,應考慮在如下的列上建立:
字段值惟一的字段(特別是標識字段),或絕大部分字段值都不重複的字段,如90%字段值都不重複的字段
按順序被訪問的字段
結果集中常常被查詢的字段
對於如下的字段,儘可能避免在其上建立彙集索引:
更新頻繁的字段。由於在數據更新時,爲保持與彙集索引的一致性必須移動表中的記錄。對數據量大的數據表而言這種移動過程是耗時的,於是是不可取的。
寬度比較長的字段。由於非彙集索引鍵值都包含彙集索引鍵,這會致使全部非彙集索引的「膨脹」,增長非彙集索引的長度,下降查詢效率。
因爲彙集索引對錶中的數據記錄的存放位置一一進行了排序,所以使用匯集索引搜索數據很快。
2. 非彙集索引(Non-Clustered Index)
非彙集索引也是基於B_樹來構造的,但它與彙集索引不一樣,這主要體如今如下兩點:
• 非彙集索引容許表中記錄的物理順序與索引順序不相同,即非彙集索引不改變表中記錄的物理順序,它只是保存着指向相應記錄的指針。一個數據表能夠同時擁有一個或多個非彙集索引。
• 非彙集索引的葉子節點包含索引鍵和指向索引鍵對應記錄的指針,而不包含數據頁(不保存實際數據,更可能是保存指向記錄的指針)。
【例子】 咱們考慮表student中對s_no字段建立的非彙集索引。其可能的非彙集索引結果如圖8.3所示。
由圖8.3所示的特色代表,非彙集索引的索引指針是容許「相交」的(這是非彙集索引的主要特色),這是由於在非彙集索引中B_樹的葉子結點保存的是記錄的指針,索引順序與數據記錄的物理順序不須要保持一致,只要索引指針正確指向相應的記錄便可。
非彙集索引與數據表是分開的,非彙集索引的改動不會致使數據表的變更。咱們能夠基於一個或多個字段建立一種或多種不一樣類型的非彙集索引。可是,正如前面指出,非彙集索引不是建立得越多越好,通常在建立這類索引的時候應該從如下幾方面考慮:
(1)在對數據表建立非彙集索引的時候,應注意如下狀況。
宜對數據量大、更新操做少的表,特別是專門用於查詢的數據表建立非彙集索引。例如,面向決策支持系統應用程序的只讀數據表。
不宜對更新操做頻繁的數據表建立非彙集索引,不然會下降系統的性能。
儘可能少對OLTP(聯機事務處理)類應用程序頻繁涉及的數據表建立非彙集索引,由於OLTP應用程序對這類表的更新操做可能很頻繁。
在建立非彙集索引時,儘可能避免涉及多字段的索引,即涉及的字段越少越好。
(2)當肯定要對一個表建立非彙集索引的時候,要選擇哪一字段或哪些字段來建立,這也是須要進一步考慮的問題。
可考慮對包含大量非重複值的字段建立非彙集索引。若是隻有不多的非重複值,如只有0和1,則查詢優化器將不使用索引,因此對這類字段不宜建立索引。
所基於字段的查詢不返回大結果集,對此字段可考慮建立非彙集索引。
對於WHERE子句中用於精確匹配查詢的字段,可考慮建立非彙集索引。
可考慮對覆蓋查詢的字段建立非彙集索引。這有利於消除對彙集索引的訪問,提升查詢效率。
函數
在建立和使用索引時常常看到「惟一索引(Unique Index)」這個術語。那麼,什麼是惟一索引?所謂惟一索引,它是指索引值惟一(沒有重複索引值)的一類索引,若是索引值不惟一,則爲非惟一索引。當對某一字段建立了惟一索引後,就不能對該字段輸入有重複的字段值。在建立表時,若是設置了主鍵,那麼SQL Server就會自動創建一個惟一索引。用戶也能夠在表建立之後再對字段建立惟一索引。
在建立惟一索引之後,SQL Server會在每次執行更新操做時都會自動檢查是否有重複的索引值,若是有則插入操做將被回滾,並同時由數據庫引擎顯示錯誤消息。
惟一索引與彙集索引和非彙集索引有什麼聯繫呢?
• 答案是「沒有」。它們只是從不一樣的角度對索引進行分類罷了,就像人能夠分爲男人和女人、也能夠分爲中國人和非中國人的道理同樣。從索引數據存儲的角度來看,索引能夠分爲彙集索引和非彙集索引;從索引值是否能夠重複的角度看,索引又能夠分爲惟一索引和非惟一索引。惟一索引既能夠是彙集索引,也能夠是非彙集索引。
post
組合索引是指使用兩個或兩個以上的字段來建立的索引。它與彙集索引等也沒有必然的聯繫,只是分類的根據不一樣罷了。
前面已經指出,在建立索引時涉及的字段越少越好,那麼爲何還要容許建立組合索引呢?
緣由:有時候須要惟一索引,但利用一個字段不能建立惟一索引,這就須要增長字段的方法實現惟一索引。
在表SC中沒有哪一字段能夠對其建立惟一索引,但把字段s_no和字段c_name組合起來就能夠建立惟一索引,由於不會出現同一個學生選修兩門或兩門以上相同課程的狀況。
性能
彙集索引的最大優勢是,當對帶有彙集索引的字段進行查詢時,會產生很高的查詢效率。這是由於,索引值相近的字段值在物理磁盤上也相互靠近,這樣就能夠大大減小磁盤轉動所須要的讀盤時間。
注意,對一個表或視圖只能建立一個彙集索引。
帶CLUSTERED選項的CREATE INDEX語句用於建立彙集索引,其語法格式以下:大數據
CREATE CLUSTERED INDEX index_name ON table_name(col_list [DESC | ASC]);
index_name表示要設定的索引名,table_name表示表名,col_list爲字段列表;若是選擇了DESC則表示建立降序索引,若是選擇了ASC(默認選項)則表示建立升序索引。
【例8.1】 建立一個彙集索引。
本例中,先建立一個空的數據表——表student2,此表與表student的區別是沒有爲它建立主健,建立代碼以下:優化
CREATE TABLE student2( s_no char(8) , s_name char(8) NOT NULL, s_sex char(2) CHECK(s_sex = '男' OR s_sex = '女’), s_birthday smalldatetime CHECK(s_birthday>='1970-1-1' AND s_birthday<='2000-1-1’), s_speciality varchar(50) DEFAULT '計算機軟件與理論’, s_avgrade numeric(3,1) CHECK(s_avgrade >= 0 AND s_avgrade <= 100), s_dept varchar(50) DEFAULT '計算機科學系' );
表student2的特色是沒有任何索引。用下列INSERT語句插入數據:
加密
INSERT student2 VALUES('20170205','賈簿','男','1994-09-03','計算機軟件與理論',43.0,'計算機系'); INSERT student2 VALUES('20170206','李思思','女','1996-05-05','計算機應用技術',67.3,'計算機系'); INSERT student2 VALUES('20170207','蒙恬','男','1995-12-02','大數據技術',78.8,'大數據技術系'); INSERT student2 VALUES('20170208','張宇','女','1997-03-08','大數據技術',59.3,'大數據技術系'); INSERT student2 VALUES('20170201','劉洋','女','1997-02-03','計算機應用技術',98.5,'計算機系'); INSERT student2 VALUES('20170202','王曉珂','女','1997-09-20','計算機軟件與理論',88.1,'計算機系'); INSERT student2 VALUES('20170203','王偉志','男','1996-12-12','智能科學與技術',89.8,'智能技術系'); INSERT student2 VALUES('20170204','嶽志強','男','1998-06-01','智能科學與技術',75.8,'智能技術系');
這些數據與表student中的數據同樣,只是插入順序不一樣。當用下列SELECT語句查看錶student2時,能夠看到如圖8.4所示的內容。
SELECT * FROM student2;
從圖8.4中能夠看到,表student2中記錄的物理順序是數據實際插入的前後順序。
接着對錶student2的s_no字段建立降序彙集索引,索引名爲myIndex1:
CREATE CLUSTERED INDEX myIndex1 -- 建立彙集索引myIndex1 ON student2(s_no DESC);
執行上述代碼,而後利用SELECT語句查看這時表student2的內容,結果如圖8.5所示。
能夠看到,這時表student2中的記錄已經按s_no降序排列,這種順序也是表student2中記錄在磁盤上的物理順序。從此在對錶student2插入數據時,將按照索引myIndex1在字段s_no上定義的順序把數據記錄插入到相應的位置(而不必定位於表的最後位置);或者說,在建立彙集索引後,每一次插入數據,系統都會對數據從新進行排序(這個過程須要時間)。所以,對那些常常插入或更新索引字段值的數據表,儘可能不要建立彙集索引。
與彙集索引不一樣,對一個數據表能夠建立多個非彙集索引。理論上,咱們能夠對任何一列或若干列的組合建立非彙集索引,只要總數不超過249個。但對於索引視圖,只能爲已定義惟一彙集索引的視圖建立非彙集索引。
帶NONCLUSTERED選項的CREATE INDEX語句可用於建立非彙集索引,但NONCLUSTERED選項能夠省略。也就說,在默認狀況下CREATE INDEX語句將建立非彙集索引。其語法格式以下:
CREATE [CLUSTERED] INDEX index_name ON table_name(col_list [DESC | ASC]);
【例8.2】 建立一個非彙集索引。
通常狀況下,對於表student,按姓名(s_name)查詢學生信息是經常使用的查詢方式,所以對列s_name建立一個非彙集索引,這對提升應用系統的查詢效率有着重要的做用。下列代碼則用於對錶student中的列s_name建立一個名爲myIndex2的非彙集索引:
CREATE NONCLUSTERED INDEX myIndex2 -- 建立非彙集索引myIndex2 ON student(s_name);
上述代碼中,關鍵字NONCLUSTERED能夠省略。
默認狀況下,在查詢時一個索引是否被運用是由查詢優化器決定的,但咱們能夠強制引用指定的索引來輔助查詢。
【例8.3】 強制引用指定的非彙集索引。
在對列s_name建立了索引myIndex2之後,能夠經過WITH子句強制查詢優化器引用索引myIndex2:
SELECT * FROM student WITH (INDEX (myIndex2)) -- 強制引用索引myIndex2 WHERE s_name='劉洋';
惟一索引的建立是使用帶UNIQUE選項的CREATE INDEX語句來實現,其語法格式以下:
CREATE UNIQUE INDEX index_name ON table_name(col_list [DESC | ASC]);
【例8.4】 建立一個惟一非彙集索引。
在本例中,對錶student的s_avgrade列建立一個惟一非彙集索引,使索引列降序排序。相應代碼以下:
CREATE UNIQUE INDEX myIndex3 -- 建立惟一非彙集索引myIndex3 ON student(s_avgrade DESC)
最理想的狀況是對空表建立惟一索引。可是也可能出現對非空表建立惟一索引的狀況。若是表非空且待建立索引的列存在重複列值,則不能建立此惟一索引。
當對某一列建立惟一索引後,在插入新數據時就不容許在此列上出現重複列值,不然將產生異常,致使插入操做失敗。
有時候基於一個字段建立的索引難以知足實際須要,而須要基於多個字段的組合才能建立符合要求的索引。也就是說,在某些狀況下須要利用多個字段來建立一個索引,這就是組合索引。
【例8.5】 建立惟一組合索引的實例。
表SC包含三個字段:s_no,c_name,c_grade,其中任意一個字段都不能惟一標識表中的記錄。但s_no和c_name的組合則能夠惟一標識表中的每一條記錄。所以,能夠基於這兩個字段建立一個名爲myIndex5的惟一組合索引。代碼以下:
CREATE UNIQUE INDEX myIndex5 ON SC(s_no DESC, c_name ASC);
該惟一組合索引是一種非彙集索引,由於選項NONCLUSTERED是默認的。咱們也能夠建立屬於彙集索引的組合索引,只需在 CREATE INDEX語句中使用CLUSTERED選項便可。
利用系統存儲過程sp_helpindex能夠得到一張數據表或視圖上的全部索引。其語法以下:
sp_helpindex [ @objname = ] 'name‘;
其中,參數[ @objname =] 'name'用於指定當前數據表或視圖的名稱。該存儲過程結果集的形式輸出指定數據表或視圖上的全部索引。結果集包含三個列:
index_name:返回索引名;
index_description:返回索引說明,如是不是彙集索引、惟一索引等信息,其中包括索引所在的文件組;
index_keys:返回對其生成索引的列。
【例8.6】 查看數據表上全部索引的實例。
本例是查看數據表student上的全部索引,代碼以下:
sp_helpindex 'student';
執行此存儲過程,結果如圖8.6所示。
圖8.6中,被降序索引的列在結果集中用減號(-)標識,即若是一個列名後綴減號(-),則表示該列被降序索引;當列出被升序索引的列(這是默認狀況)時,只帶有該列的名稱。
當前數據庫中的全部索引都保存在目錄視圖sys.indexes中,所以經過查詢該表能夠得到當前數據庫中全部索引的詳細信息。
【例8.7】 查看當前數據庫的全部索引。
本例用於查看當前數據庫的全部索引,相應的SELECT語句以下:
USE MyDatabase; GO SELECT * FROM sys.indexes;
當一個索引再也不須要的時候,可用DROP INDEX語句將之刪除。該語句最簡單的語法格式能夠表示爲:
DROP INDEX index_name ON table_name;
也能夠將表名前綴,寫成:
DROP INDEX table_namet.index_name;
【例8.8】 刪除索引實例。
本例是將表student中的索引myIndex2刪除,相應代碼以下:
DROP INDEX myIndex2 ON student; --也能夠寫成: DROP INDEX student.myIndex2
另外,在建立表的時候,可能設置了PRIMARY KEY或UNIQUE約束,這時會自動生成與約束名同名的索引。這種索引的刪除不能使用DROP INDEX語句來完成,但可使用ALTER TABLE DROP CONSTRAINT語句將其刪除。
【例8.9】 刪除定義PRIMARY KEY約束時建立的索引。
刪除表student中定義PRIMARY KEY約束時建立的索引 PK__student__2F36BC5B24DD5622,實現代碼以下:
ALTER TABLE student DROP CONSTRAINT PK__student__2F36BC5B91406173
視圖在視覺上也是一張由行和列構成「數據表」,但它不是真正的數據表,而是一張虛擬的數據表(虛表)。實際上,視圖在本質上是一個命令集,當「打開」它時將由這些命令從一張或多張數據表中抽取數據,這些數據便在視覺上構成了一張「數據表」,而這些被從中抽取數據的數據表一般稱爲視圖的基本表或基礎表(簡稱基表)。因此,視圖也能夠當作是一張或多張數據表的一個數據窗口,它是動態生成的。
視圖離不開它的基表,它是按照某種條件和要求對基表進行篩選的結果;離開了基表,視圖是沒有意義的。基表中數據的變化將實時反映到視圖當中,針對視圖的操做其實是對基表進行操做。
圖8.7給出了由一張表生成視圖的示意圖。
在視覺上,視圖和數據表幾乎是如出一轍,具備字段、記錄和數據項,也能夠進行查詢、更新等操做。但視圖畢竟不是數據表,其所包含的數據並不以視圖結構存儲在數據庫中,而是存儲在視圖的基表中。所以,在對視圖進行操做時會受到許多限制。正是這些限制爲數據庫的安全提供了一種保障機制。再加上其餘的相關機制,使得視圖較數據表具備獨特的優點。這些優點主要體如今如下幾個方面:
(1)提供個性化的數據顯示功能
數據表的建立通常是出於對系統的設計與實現來考慮的,主要是面向系統設計人員和程序編寫人員,而不是面向用戶。可是,對一個用戶而言,他感興趣的多是一張或多張數據表中的部分數據。視圖則爲用戶可以看到他們感興趣的特定數據提供了一種有效的窗口觀察機制。
(2)簡化數據的操做
用戶感興趣的數據可能分散在多張數據表中,將這些用戶感興趣的數據檢索出來,可能須要多種操做。即便這些數據在同一張表中,把它們檢索出來也可能須要一些複雜而繁瑣的操做。若是將這些常用的操做(如鏈接、投影、聯合查詢和選擇查詢等)定義爲視圖,那麼用戶每次對特定的數據執行進一步操做時,沒必要重複指定全部條件和限定。
假如出於某種實際應用要求,須要屢次、重複執行某一個複合查詢,則最好將該複合查詢定義爲一個視圖,之後只需對該視圖查詢便可,從而簡化對數據的訪問方式。此外,也簡化了用戶權限的管理操做,由於只需授予用戶使用某些視圖的權限,而沒必要指定用戶只能使用表的特定列。
(3)自組織數據
視圖容許用戶以不一樣的方式查看數據,即便他們同時使用相同的數據時也是如此。
(4)組合分區數據
用戶能夠未來自不一樣數據表的兩個或多個查詢結果集定義爲一個視圖,稱爲分區視圖。經過使用分區視圖,對用戶來講他操做的是一張「表」,而不是多張表,能夠對它像一張表同樣進行查詢等操做,而無需對基表進行操做。
(5)便於數據共享
對一個基表能夠定義多個用戶視圖。用戶能夠經過使用本身的視圖來實現對基表的操做,從而能夠垂手可得地實現同一張表爲多個用戶服務的目的。
(6)提升安全性
用戶只能看到視圖中所定義的數據,而看不到基表中的其餘數據以及表的其餘信息。這種機制能夠加強數據的安全性。
但視圖也有其自身的缺點,這主要體如今:
(1)相對低效
視圖在本質上是一些命令的集合。在對視圖進行操做的時候,除了執行鍵入的SQL語句中的查詢或更新外,還要須要執行視圖自己所包含命令。所以,這在必定程度上下降了查詢效率。
(2)有限的更新操做
視圖主要是用於查詢,對更新操做受到不少的限制。目前,可更新的視圖要求其基表是單表(準確地說,一次更新操做不能同時涉及到兩個或兩個以上的基表),而且用於定義視圖的SELECT語句不能包含GROUP BY或HAVING子句。另外,若是SELECT語句中包含了彙集函數、計算列或DISTINCT子句,相應的視圖也不能更新。
視圖是用CREATE VIEW語句來建立,其簡要的語法以下:
CREATE VIEW view_name [(column [,...n])] AS select_statement;
其中,view_name表示要建立的視圖的名稱;select_statement爲SELECT查詢語句;column [,...n]表示視圖中字段的名稱,若是未指定 column,則視圖的字段名將與 SELECT查詢中的字段名相同。
【例8.10】 建立與基表徹底相同的視圖。
本例中,將建立與基表student「擁有」徹底相同內容的視圖myView1。固然這種視圖沒有什麼實際意義,但它是咱們認識視圖的起點。代碼以下:
CREATE VIEW myView1 AS SELECT * FROM student;
執行上述代碼,將在當前數據庫中建立名爲myView1的視圖。使用下列SELECT語句能夠查詢該視圖中的數據,如圖8.8所示:
SELECT * FROM myView1
能夠看到,視圖myView1中的數據與表student中的數據是徹底同樣的
【例8.11】 建立包含基表中部分數據的視圖,並給視圖設定新的中文字段名。
實際上,視圖的重要應用之一是充當基表的數據窗口,透過這個窗口咱們能夠看到咱們感興趣的數據。本例中,對錶student中平均成績(s_avgrade)在60或60分以上的學生,將其學號(s_no)、姓名(s_name)、專業(s_speciality)、平均成績(s_avgrade)和系別(s_dept)定義爲視圖myView2。相應代碼以下:
CREATE VIEW myView2(學號,姓名,專業,平均成績,系別) AS SELECT s_no, s_name, s_speciality, s_avgrade, s_dept FROM student WHERE s_avgrade>=60;
執行上述語句後,經過執行下列SELECT語句來查詢myView2中的數據,結果如圖8.9所示。
SELECT * FROM myView2
--注意,視圖myView2包含的字段名爲「學號」、「姓名」、「專業」、「平均成績」和「系別」, --而s_no, s_name, s_speciality, s_avgrade, s_dept不是該視圖的字段名了, --所以下列的SELECT語句都是錯誤的: SELECT s_no, s_name, s_speciality, s_avgrade, s_dept FROM myView2 SELECT s_no, s_name FROM myView2 --而下列的SELECT則是正確的: SELECT 學號,姓名,專業,平均成績,系別 FROM myView2
【例8.12】 建立帶有兩個基表的視圖。
若是一個視圖帶有兩個基表,這說明在其CREATE VIEW語句中運用了鏈接查詢,其中涉及到兩張數據表。下面是建立這種視圖的SQL代碼:
CREATE VIEW myView3 AS SELECT student.s_no 學號, s_name 姓名, s_sex 性別, s_speciality 專業, s_dept 系別, c_name 課程名稱, c_grade 課程成績 FROM student, SC WHERE student.s_no = SC.s_no
實際上,在不少狀況下,視圖能夠像數據表同樣使用。好比,能夠用視圖去更新另一個數據表,實現數據初始化等功能。
【例8.13】 用視圖更新數據表。
在例5.30中,爲了用表SC中的課程成績(c_grade)去更新(初始化)表student中的平均成績s_avgrade字段,咱們定義了一個臨時數據表tmp_table。實際上,能夠用視圖來代替這個數據表,較少存儲空間的消耗。方法以下:
首先,經過按學號分組的方法求各個學生的平均成績,並將其學號和平均成績定義稱爲視圖tmp_view
CREATE VIEW tmp_view AS SELECT s_no, AVG(c_grade) as s_avgrade FROM SC GROUP BY s_no
其次,表student和視圖tmp_view的聯繫是基於字段s_no的(1:1)聯繫,所以咱們能夠用視圖tmp_view中的平均成績字段s_avgrade去更新表student中的平均成績字段s_avgrade:
UPDATE student SET s_avgrade = b.s_avgrade FROM student as a JOIN tmp_view as b ON a.s_no = b.s_no
【例8.14】 建立帶參數的「視圖」。
建立一個「視圖」,要求其可以顯示平均成績在指定分數段內的學生信息。分數段由兩個參數來定義,這樣咱們能夠利用函數來實現這個功能,函數的定義代碼以下:
CREATE FUNCTION myFunView(@a float, @b float) RETURNS TABLE AS RETURN ( SELECT * FROM student WHERE s_avgrade >= @a and s_avgrade <= @b );
執行上述代碼,建立函數myFunView。此後,能夠像視圖同樣查詢該函數,但要帶兩個參數。好比,查詢平均成績在60到90之間的學生,相應的SELECT代碼以下:
SELECT * FROM myFunView(60,90)
也能夠像視圖同樣,對該函數進行更新操做。比例,將平均成績在60到90之間的學生的系別(s_dept)所有改成「智能技術系」,相應代碼以下:
UPDATE myFunView(60,90) SET s_dept= '智能技術系‘
注意,這種帶參數的「視圖」並非視圖,而是一種函數,但它具備視圖的大部分特性。
更新視圖是指經過視圖更新其基表中的數據,這跟更新數據表的方法同樣,只需將視圖名看成數據表名便可。
【例8.15】 將視圖myView2中的平均成績所有設置爲80分。
相應代碼以下:
UPDATE myView2 SET 平均成績 = 80;
執行上述語句後,視圖myView2中的平均成績所有變爲80。實際上,這個修改操做是修改表student中字段s_avgrade的字段值,將其所有改成80分。
但因爲視圖不是真正的數據表,對其進行的更新操做會受到諸多的限制。最明顯的一個限制是:任何針對視圖的修改操做不能同時影響到兩個或兩個以上的基表。
【例子】 對於視圖myView3,下列的UPDATE語句是錯誤的:
UPDATE myView3 SET 性別 = '女', 課程成績 = 99
這是由於視圖myView3中的「性別」和「課程成績」分別來自表student中的字段s_sex和表SC中的字段c_grade,即該UPDATE語句會影響到表student和SC,所以該UPDATE語句是錯誤的。
但下面兩條UPDATE語句都是可執行的,由於它們各自都隻影響到一個數據表:
UPDATE myView3 SET 性別 = '女’ UPDATE myView3 SET 課程成績 = 99
對視圖的數據插入和刪除操做與對數據表的數據插入和刪除操做也分別同樣,但前提是不能違反表的完整性約束、一個操做不能影響到兩個或兩個以上的基表。
視圖的刪除可用DROP VIEW語句來實現,其語法以下:
DROP VIEW [ schema_name . ] view_name [ ...,n ] [ ; ]
其中,view_name爲要刪除的視圖的名稱,schema_name爲視圖所屬架構的名稱。
【例8.16】 刪除視圖的實例。
刪除視圖myView1和myView2,可用下面的DROP VIEW語句來完成:
DROP VIEW myView1, myView2;
須要說明的是,使用DROP VIEW語句刪除視圖時,並無刪除其基表中的數據,而只是刪除視圖的定義代碼及其與其餘對象的關係。因此,刪除視圖時沒必要擔憂會刪除數據表中的數據。
若是視圖的定義代碼沒有被加密,咱們能夠查看它的定義代碼。
【例8.17】 查看視圖的定義代碼。
查看視圖myView1的定義代碼,能夠利用系統存儲過程sp_helptext來實現。其實現代碼以下:
sp_helptext myView1;
執行上述存儲過程,結果如圖8.10所示。
視圖的結構信息等能夠利用系統存儲過程sp_help來查看。
【例8.18】 查看系統的結構信息。
本例將查看視圖myView1,使用系統存儲過程sp_help的代碼以下:
sp_help myView1;
執行上述代碼,結果如圖8.11所示。
當前數據庫中全部視圖的信息都包含在系統目錄視圖sys.views中,所以經過查詢該視圖能夠得到當前數據庫中全部視圖的信息。
【例8.19】 查看當前數據庫中全部用戶定義的視圖。
將數據庫MyDatabase設置爲當前數據庫,而後查詢其中包含的全部用戶定義的視圖的名稱。實現代碼以下:
USE MyDatabase; GO SELECT name '視圖名稱(當前數據庫)' FROM sys.views; GO
執行上述代碼,結果如圖8.12所示。
若是要查看全部數據庫中的視圖,則可利用下列的語句來完成:
SELECT name '視圖名稱(全部數據庫)' FROM sys.all_views;