SQL Server 2000的視圖中必須小心使用*符號(hào)
有些朋友看到這個(gè)標(biāo)題可能會(huì)有疑問(wèn),難道在視圖中使用*符號(hào)還有何要注意的地方嗎?對(duì)于這個(gè)問(wèn)題,我們先不必回答,先看一下例子吧。
我這里,使用的數(shù)據(jù)庫(kù)是SqlServer2000自帶的Northwind,這樣方便大家自己私下里測(cè)試。首先,創(chuàng)建兩個(gè)視圖,視圖的腳本如下:
--視圖 vCustomersA
create view vCustomersA
as
select CustomerID ,CompanyName,ContactName,ContactTitle,
Address,City,Region,PostalCode,Country,Phone,Fax
from dbo.Customers
go
--視圖 vCustomersB
create view vCustomersB
as
select * from vCustomersA
go
然后,使用這兩個(gè)視圖查詢(xún)客戶(hù)ID為ALFKI的資料,查詢(xún)語(yǔ)句如下:
select * from vCustomersA where CustomerID = 'ALFKI'
select * from vCustomersB where CustomerID = 'ALFKI'
查詢(xún)的結(jié)果如下:
一切正常,這個(gè)時(shí)候,需求發(fā)生了變化,我們需要改動(dòng)vCustomersA,改動(dòng)后的腳本如下:(為了說(shuō)明問(wèn)題,我們只是把CompanyName和ContactName互換一下位置)
--改動(dòng)后的視圖vCustomersA
alter view vCustomersA
as
select CustomerID ,ContactName,CompanyName,ContactTitle,
Address,City,Region,PostalCode,Country,Phone,Fax
from dbo.Customers
go
這個(gè)時(shí)候,當(dāng)我們?cè)俅问褂靡晥DvCustomersB查詢(xún)客戶(hù)ID為ALFKI的資料的時(shí)候,錯(cuò)誤已經(jīng)悄然來(lái)臨,你注意到了嗎?讓我們來(lái)看一下這兩個(gè)視圖的查詢(xún)結(jié)果吧,查詢(xún)語(yǔ)句如下:
select * from vCustomersA where CustomerID = 'ALFKI'
select * from vCustomersB where CustomerID = 'ALFKI'
查詢(xún)的結(jié)果發(fā)生變化。你注意到數(shù)據(jù)的異常了嗎?使用視圖vCustomersB查詢(xún)的結(jié)果出現(xiàn)了錯(cuò)誤,CompanyName顯示的資料是:Maria Anders,而在視圖vCustomersA查詢(xún)的結(jié)果中CompanyName是:Alfreds Futterkiste。我們僅僅是在vCustomersA中互換了兩個(gè)字段的位置,再次使用vCustomersB查詢(xún)數(shù)據(jù)卻發(fā)生了數(shù)據(jù)錯(cuò)位的現(xiàn)象,這是什么原因?qū)е碌哪兀?
帶著這個(gè)問(wèn)題,讓我們?nèi)チ私庖幌拢沃^視圖?在Sql Server2000的幫助文檔中是這樣描述視圖的,定義如下:“視圖是一個(gè)虛擬表,其內(nèi)容由查詢(xún)定義,同真實(shí)的表一樣,視圖包含一系列帶有名稱(chēng)的列和行數(shù)據(jù)。但是,視圖并不在數(shù)據(jù)庫(kù)中以存儲(chǔ)的數(shù)據(jù)值集形式存在。行和列數(shù)據(jù)來(lái)自由定義視圖的查詢(xún)所引用的表,并且在引用視圖時(shí)動(dòng)態(tài)生成。”通過(guò)這個(gè)定義我們可以看出,視圖是一個(gè)虛擬的表,它僅僅包括視圖的定義腳本,查詢(xún)的內(nèi)容則是動(dòng)態(tài)的生成。當(dāng)我們創(chuàng)建了一個(gè)視圖以后,視圖的腳本會(huì)保存到當(dāng)前數(shù)據(jù)庫(kù)的系統(tǒng)表syscomments里,我們可以通過(guò)系統(tǒng)提供的存儲(chǔ)過(guò)程:sp_helptext查詢(xún)得到視圖的定義腳本。從定義上看,好像并不能得到我們想要的答案,那么我們就先不管Sql Server2000是如何實(shí)現(xiàn)視圖的,我們先來(lái)解決一下當(dāng)前的問(wèn)題(我上面提到的)。可能有些朋友已經(jīng)知道了解決問(wèn)題的辦法了,那就是把vCustomersB的定義腳本重新執(zhí)行一下(其實(shí)只需要把create換成alter執(zhí)行一下就可以),腳本如下:
--重新執(zhí)行一下vCustomersB的定義腳本
alter view vCustomersB
as
select * from vCustomersA
go
那么,除了這個(gè)方法以外,其實(shí)SqlServer2000也提供了一個(gè)擴(kuò)展存儲(chǔ)過(guò)程sp_refreshview來(lái)幫我們做這件事情,調(diào)用的腳本如下:
--刷新指定視圖的元數(shù)據(jù)
exec sp_refreshview 'vCustomersB'
我個(gè)人目前就知道這兩個(gè)辦法,不知道,你還有沒(méi)有其他的辦法,有的話可以一起分享一下。
sp_refreshview的功能描述為:“刷新指定視圖的元數(shù)據(jù)。由于視圖所依賴(lài)的基礎(chǔ)對(duì)象的更改,視圖的持久元數(shù)據(jù)會(huì)過(guò)期。”由于sp_refreshview的代碼被封裝了(沒(méi)有公開(kāi)),所以我們看不到它的內(nèi)部實(shí)現(xiàn),不過(guò)看了這個(gè)存儲(chǔ)過(guò)程的描述,你是否對(duì)視圖有了新的認(rèn)識(shí)呢?
從這里,我們可以看到,當(dāng)我們使用一個(gè)視圖查詢(xún)數(shù)據(jù)的時(shí)候,其實(shí)我們是在使用視圖的元數(shù)據(jù)來(lái)查詢(xún)的,當(dāng)視圖依賴(lài)的對(duì)象發(fā)生了變化以后,視圖的元數(shù)據(jù)就需要更新,這樣,使用視圖時(shí)才不會(huì)違背我們的意愿。
知道了問(wèn)題的產(chǎn)生的原因后,那么我們?cè)谥匦滦薷囊粋€(gè)表或視圖的腳本時(shí),我們就需要更新依賴(lài)于該對(duì)象的視圖,否則就會(huì)出現(xiàn)意想不到的錯(cuò)誤。如何找到依賴(lài)于該對(duì)象的對(duì)象(包括視圖,觸發(fā)器,存儲(chǔ)過(guò)程)呢?SqlServer2000在該數(shù)據(jù)庫(kù)的系統(tǒng)表sysdepends里記錄這些依賴(lài)關(guān)系,所以你可以查詢(xún)?cè)摫慝@取你想要的信息,但其實(shí),你可以通過(guò)使用系統(tǒng)提供的存儲(chǔ)過(guò)程:sp_depends來(lái)獲取該對(duì)象的所依賴(lài)的對(duì)象(返回的第一個(gè)表)以及依賴(lài)于該對(duì)象的對(duì)象(返回的第二個(gè)表),腳本如下:
--查詢(xún)vCustomersA的依賴(lài)的對(duì)象以及依賴(lài)于vCustomersA的對(duì)象
exec sp_depends 'vCustomersA'
查詢(xún)的結(jié)果如下圖:
注:sp_depends的代碼是公開(kāi)的,有興趣的可以看一下其實(shí)現(xiàn)過(guò)程。
到此,你應(yīng)該明白,當(dāng)你更新你的表或視圖的時(shí)候,你還要刷新依賴(lài)于這些對(duì)象的視圖的元數(shù)據(jù),即需要調(diào)用sp_refreshview來(lái)刷新依賴(lài)于該對(duì)象的視圖。但是你在查詢(xún)依賴(lài)于一個(gè)表或者視圖的對(duì)象集合的時(shí)候需要注意的一點(diǎn)是,在你更新了一個(gè)表或視圖之后,那些之前創(chuàng)建的依賴(lài)于該表或視圖的依賴(lài)關(guān)系將會(huì)丟失(你更新的表或視圖所依賴(lài)的對(duì)象集合不會(huì)丟失),用我之前的例子來(lái)看,vCustomersB依賴(lài)于vCustomersA,那么當(dāng)我們修改了vCustomersA以后,vCustomersB與vCustomersA之間的依賴(lài)關(guān)系將會(huì)丟失而vCustomersA所依賴(lài)的Customers將不會(huì)丟失(依賴(lài)關(guān)系在對(duì)象創(chuàng)建或更新時(shí)創(chuàng)建,更新時(shí),會(huì)把先前的依賴(lài)關(guān)系刪掉)。(調(diào)用sp_depends你就可以看出來(lái)這種微妙的變化)
希望在你閱讀了本文以后,你在使用視圖的時(shí)候會(huì)更加的得心應(yīng)手,避免錯(cuò)誤發(fā)生。文中有不對(duì)的地方歡迎指正批評(píng)!
