End Function %> 這僅僅是調用一個存儲過程,從而得到書的類型,同時創建一個SELECT列表。上述代碼的缺點在于每次調用該函數都必須訪問數據庫。因此,重新修改這個函數。 <% Function BookTypes()
Dim rsBookTypes Dim strQuote Dim strList
' See if the list is in the cache strList = Application("BookTypes") If strList = "" Then ' Not cached, so build up list and cache it strQuote = Chr(34)
Set rsBookTypes = Server.CreateObject ("ADODB.Recordset")
' Get the book types rsBookTypes.Open "usp_BookTypes", strConn
9.4.1 使用數據整形 應用數據整形必須: · 使用MSDataShape OLEDB提供者。 · 使用一種特殊的整形語言,它是SQL的一種擴充,允許構造層次。 盡管使用新的提供者,連接字符串的實際改變不會太大。這是因為仍然需要從某處獲取數據。因此,可以這么做: PRovider=MSDataShape; Data Provider=SQLOLEDB; Data Source=... 這里用MSDataShape作為提供者,而正常的Provider變為Data Provider,而連接字符串的剩余部分保持不變。 為數據整形創建連接字符串的簡便方法是從創建正規的連接字符串開始,然后附加到數據整形塊的最后。例如,考慮以下正規的連接字符串。 strConn = "Provider=SQLOLEDB; Data Source=Kanga; " & _ " Initial Catalog=pubs; User Id=sa; PassWord=" 可以像下面這樣為數據整形提供者創建連接字符串。 strConn = "Provider=MSDataShape; Data " & strConn 這將提供者設置為MSDataShape,而Data Provider成為實際的數據源。初始的連接字符串已經包含了"Provider= ",所以為了獲得正確的連接細節,只須前面加上Data。 1. 整形語言 整形語言有其自己的語法,但這里我們不打算涉及其構造,它已包含在ADO文獻中。大多數情況下會采用以下命令。 SHAPE {parent command} [AS parent alias] APPEND ({child command} [AS child alias] RELATE parent_column TO child_column) [AS parent_column_name] 要理解這一點,最簡單的方法是看一個實例,以Publishers和Titles為例。 SHAPE {SELECT * FROM publishers} APPEND ({SELECT * FROM Titles} RELATE Pub_ID TO PubID) AS rsTitles 第一行是父記錄集,第二行則是子記錄集。第三行指明了關聯父、子記錄集的兩個字段。這個例子中兩個表都有一個名為Pub_ID的字段(出版社ID字段)。這個命令返回一個包含出版社的記錄集,在記錄集的最后又附加了一個含有子記錄集的新列(類型為adChapter)。該列名為AS子句給出,在本例中是rsTitles。 adChapter類型只是說明了該字段含有一個子記錄集。我個人認為,adChild或adRecordset更合適。 通過遍歷Fields集合,可以很容易看到父記錄集的字段的情況。對于上面的SHAPE命令,得到圖9-9所示的結果:
圖9-9 執行SHAPE命令后的結果 訪問子記錄集 現在,我們有了一個子記錄集,它是另一個記錄集的一個字段,那么如何訪問這個子記錄集呢?很簡單,可以使用字段的Value屬性來建立另一個記錄集。 Set rsTitles = rsPublishers("rsTitles").Value 可以遍歷父記錄集,對應于每個父記錄可以得到一個子記錄集。下面的代碼能實現這一點。通常以包含文件、變量聲明開始。 <!-- #INCLUDE FILE="../Include/Connection.asp" --> <% Dim rsPublishers Dim fldF Dim strShapeConn Dim strShape
Set rsPublishers = Server.CreateObject ("ADODB.Recordset") 現在創建連接字符串。 ' Create the provider command strShapeConn = "Provider=MSDataShape; Data " & strConn 接下來,輸入實際的整形命令。這將創建一個包含出版社的父記錄集和一個含有書名的子記錄集。 ' now the shape command strShape = "SHAPE {SELECT * FROM Publishers}" & _ " APPEND ({SELECT * FROM Titles}" & _ " RELATE Pub_ID TO Pub_ID) AS rsTitles" 然后正常打開記錄集。 ' Open the shaped recordset rsPublishers.Open strShape, strShapeConn 像正常的記錄集一樣,能夠遍歷記錄。 ' loop through the publishers Response.Write "<UL>" While Not rsPublishers.EOF Response.Write "<LI>" & rsPublishers("pub_name") 為了訪問子記錄集,設置一個變量來指向那個包含子記錄集的字段的Value值。本例中該變量為rsTitles。 ' now the titles Response.Write "<UL>" Set rsTitles = rsPublishers("rsTitles").Value 變量rsTitles在這里是個記錄集,其作用同普通的記錄集相同。因此,可以遍歷該記錄集的值,該值只包含與父出版者匹配的書名。 ' loop through the titles While Not rsTitles.EOF Response.Write "<LI>" & rsTitles("title") rsTitles.MoveNext Wend Response.Write "</UL>"
' move to the next publisher rsPublishers.MoveNext Wend Response.Write "</UL>"
rsPublishers.Close Set rsPublishers = Nothing Set rsTitles = Nothing %> 于是得到一份令人滿意的出版社與書名的列表,如圖9-10所示:
圖9-10 整形后的書名列表 用一些DHTML代碼和一些額外的標記,就能輕松地隱藏起書名,并且只有選擇出版社時才顯示相應的書名。 2. 多個子記錄集 如果對于每個記錄集僅能有一個子記錄集,那么數據整形就不夠完善。但數據整形是極其靈活的。例如可以使用下面的程序來為出版社引用標題和雇員。 SHAPE {select * from publishers} APPEND ({select * from titles} RELATE pub_id TO pub_id) AS rsTitles, ({select * from employee} RELATE pub_id To pub_id) AS rsEmployees 只需在APPEND子句后加上其他子記錄集,就能得到圖9-11的結果:
圖9-11 多個子記錄集的結果 訪問子記錄集的方法并沒有改變,仍舊可以用列的Value屬性訪問子記錄集。只是此時有兩個子記錄集,因此需要使用兩個變量。 Set rsTitles = rsPublishers("rsTitles").Value
Set rsEmployees = rsPublishers("rsEmployees").Value 3. 孫代記錄集 在子記錄集自身還包含子記錄集的情況下,可能會出現孫代記錄集。例如: SHAPE {SELECT * FROM Publishers} APPEND (( SHAPE {SELECT * FROM Titles} APPEND ({SELECT * FROM Sales} RELATE Title_ID TO Title_ID) AS rssales) RELATE Pub_ID TO Pub_ID) AS rsTitles 在第一個APPEND子句內是另一個SHAPE命令,而不是一個SELECT語句。與多個子記錄集的例子相似,訪問孫代記錄集的方法是相同的。 Set rsTitles = rsPublishers("rsTitles").Value
Set rsSales = rsTitles("rsSales").Value 對子和孫記錄集的深度沒有理論上的限制,但也不可能建立多于三級或四級的子記錄集。
9.4.2 性能 數據整形不會自動改善性能,但正確使用時可以改善性能。重要的是記住其工作方式: · 對于SHAPE命令中的SELECT語句,將完全取出表中的數據。SQL語句并沒有得到任何優化。這樣,如果在父表中加入WHERE子句來限制父記錄集的記錄數,仍能得到所有的子記錄集。例如: SHAPE {SELECT * FROM Publishers WHERE State='CA'} APPEND ({SELECT * FROM Titles} RELATE Pub_ID TO Pub_ID) AS rsTitles APPEND語句返回所有的標題,并不僅限于加州(CA)的出版社。記住,這不是SQL JOIN語句。在加州的出版社以及所有的標題都被提取了,這樣就完成了數據整形。 · 可以使用存儲過程,這會提高一點性能。然而,如果使用一個參數化的存儲過程產生子記錄集,那么每次訪問子記錄集時,這個存儲過程都會執行。這意味著,子記錄集不在前端代碼中編程產生,而是只包含存在存儲過程產生的那么記錄。不足之處是增加了服務器的工作,但這樣卻能保證數據是最新的,因為每次需要時就從數據庫中提取數據。 在下一章當我們著眼于客戶端數據時,會看到更多有關經過整形的記錄集的介紹。