現在的資訊系統越來越複雜,它們的資料庫中的資料結構也越來越複雜,表和欄位變多了,表間關係也越來越多。面對如此複雜的資料結構,各大報表工具各顯神通,想盡一切辦
法誓要從中獲得資料。
首先考察資料結構的複雜性的特點。在這裡以微軟的示範資料庫
nwind.mdb為例子進行分析,現在要出訂單明細報表,則涉及到的資料結構
可以發現這5張表的資料群組成了一個3層的樹狀結構。第一層是Customers的資料,第二層是Orders,Employees組成的資料,第三層是OrderDetails,Products組成的。其意思就是說
資料庫中存在好幾個客戶,一個客戶有多個訂單,一個訂單有多個貨物。
面對這種比較複雜的資料,傳統的報表工具由於採用兩層的資料來源模型,因此需要一次性擷取資料,採用眉毛鬍子一起抓的思想,這就導致可能需要編寫複雜的SQL語句,例如對於
訂單明細報表,SQL語句可以為"SELECT Customers.CompanyName, Customers.ContactName, Customers.Phone,
OrderDetails.*, Orders.OrderDate,
Products.ProductName, Employees.FirstName, Employees.LastName
FROM ((Orders
INNER JOIN (OrderDetails
INNER JOIN Products ON OrderDetails.ProductID = Products.ProductID)
ON Orders.OrderID = OrderDetails.OrderID)
INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID)
INNER JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID",如此複雜的SQL語句我是寫不出,也不想寫,個人認為複雜SQL語句壞處多多,尤其是JOIN
子語句,應盡量避免。SQL語句寫出來後,在報表範本中還需要進行多次分組才能組織出報表樣式。
若採用多層報表資料來源模型,則採用了眉毛鬍子分別抓的指導思想,處理起來從容不迫,此時擷取資料的原理
其詳細步驟為
- 對於Customers節點,執行SQL語句"Select CompanyName , ContactName , CustomerID , Phone From Customers"獲得客戶列表
,將查詢所得的欄目分別分配到CompanyName,ContactName
, 訂單列表 , Phone
資料來源子節點。
- Customers節點遍曆所有的查詢所得的記錄行時,每處理一行,都遞迴調用子節點處理資料的過程。對於訂單列表
節點,它有子節點,因此其處理資料的過程是,首先執行SQL語句"Select
Orders.OrderID , Orders.OrderDate , Orders.EmployeeID , Employees.EmployeeID , Employees.FirstName , Employees.LastName From Orders ,
Employees where orders.employeeid = Employees.EmployeeID
and orders.CustomerID= 當前處理的CustomerID欄目的值",例如Customers節點處理CustomerID為“1234”的記錄時,訂單列
表執行的SQL語句為"Select
... From From Orders , Employees where orders.employeeid = Employees.EmployeeID and orders.CustomerID=1234"
, 也就時說訂單列表節點出執行的SQL語句是根據當前節點的值而改變的。訂單列表節點查詢成功後,然後將查詢所得的欄目分配到
OrderID , OrderData
等子節點,其中 欄目 Orders.OrderID分配給了 訂單詳細內容
子節點 。
- 類似的,對於訂單詳細內容,執行的SQL語句為"Select OrderDetails.ProductID ,
OrderDetails.UnitPrice , OrderDetails.Discount , Products.ProductName , OrderDetails.Quantity ,( OrderDetails.UnitPrice
* OrderDetails.Quantity * ( 1 - OrderDetails.Discount )) as TotalCount From
OrderDetails , Products where OrderDetails.ProductID = Products.ProductID
And OrderDetails.OrderID = 當前處理的訂單號",查詢所得的欄目分別分配到了它的子節點,其中
TotalCount 欄目分配到了總金額子節點。
執行的SQL語句依次可能為,此處欄位列表用 ...表示
- Select ... From Customers
- Select ... From Orders , Employees where orders.employeeid = Employees.EmployeeID and orders.CustomerID='1234'
- Select ... From OrderDetails , Products where OrderDetails.ProductID = Products.ProductID And OrderDetails.OrderID =
100
- Select ... From OrderDetails , Products where OrderDetails.ProductID = Products.ProductID And OrderDetails.OrderID =
101
- Select ... From Orders , Employees where orders.employeeid = Employees.EmployeeID and orders.CustomerID='5678'
- Select ... From OrderDetails , Products where OrderDetails.ProductID = Products.ProductID And OrderDetails.OrderID =
201
- Select ... From OrderDetails , Products where OrderDetails.ProductID = Products.ProductID And OrderDetails.OrderID =
202
如此看出,這種多層資料來源的使用有利有弊。好處有
- 處理過程符合一般的編程邏輯,便於對資料來源結構的理解和設計。
- 提供了充分的自由度,可以不依賴外部編程來處理大部分複雜的資料庫結構。
- 此過程中使用的SQL語句簡單可靠,很容易理解,而且執行效率高。
- 這種多層的資料來源結構很大程度上就反映了資料庫中的資料結構。資料來源樹狀結構直接映射了資料庫中各條記錄組成的樹狀結構,只要瞭解資料結構就可以很自然的套這這
種結構來編製報表資料來源。某種程度上可以進行資料來源結構和資料結構的相互檢查。
當然弊端還是有的,最大的就是大大增加了執行SQL語句的次數,影響報表執行效率。當資料來源結構層數越多,執行的SQL語句個數將以指數方式增長,因此實際應用中資料來源層數
必須有所限制,而且設計良好的資料庫資料結構有助於控制資料來源層數。
面對多層資料來源的好處和弊端,這需要權衡,個人認為大部分情況下利大於弊,主要原因有
- 隨著電腦硬體和基礎軟體的發展,資料庫查詢速度越來越快,這可以一定程度上彌補SQL語句數量增加的影響。
- 隨著資訊系統規模不斷膨脹,複雜的資料結構也是越來越多,若採用傳統模式獲得報表資料,則程式中分布了很多複雜難懂的SQL語句,這非常不利於系統的開發和維護。相
對於一般的程式碼,SQL語句沒有原始碼控制,沒有編寫規範,注釋和文檔也很少,其含義也更抽象難懂,而且少數的資料庫高手才能編寫和維護複雜的SQL語句,因此使用大量
複雜SQL語句是不明智的。
- 多層資料來源結構符合一般的編程邏輯,也反映了資料庫的資料結構,因此比較容易編製和理解,知道瞭解資料庫結構就會理解多層資料來源結構,可以讓很多有基礎的經過培
訓的人來編製和維護資料來源結構,因此可以讓普通群眾編製大部分報表資料來源而不必驚動高手,降低報表編製成本。
- 多層資料來源結構提供了充分的自由度,可以處理大部分資料結構而無需編程,這就為開發報表模組而無需編程打下了堅實的基礎。
多層資料來源模型是本人剛剛提出來的,其思想還不成熟不完善,希望大家多多指點。
XDesigner 軟體工作室 2006-8-31