在軟體專案中,經常會遇到層次資料的處理問題,比如產品分類、樹型目錄、企業組織結構等等。一般情況下,這些資料不得不儲存在關聯式資料庫中,由於關聯式資料庫表是扁平的二維結構,所以必須將層次資料平面化,才能適應關係模型的儲存訪問模式。目前基於此的轉換方法很多,流行的主要有四種:多表模式、鄰接表模式、編碼模式、改進的前序前歷模式。本文在收集整理的基礎上,通過例項對比、分析、**,希望給不熟悉的朋友提供一些參考。
首先給出乙個問題,是乙個商品分類的例子,需要在關聯式資料庫中儲存和處理,為了簡便起見,分類的層次盡量的少,並且在下文中只討論處理分類,而並不涉及到具體產品內容。如圖所示。
一、多表模式:
多表模式就是用多表來儲存層次資料,方法是每一層用一張表表示,這是一種非常原始的方法,不過很好理解,在資料層次很少的,三層以下,特別是兩層中得到了廣泛的應用。上面的問題可以用三張表分解,根「商品」這一層在此可以是虛擬的,表中可以省略。
1、 一級分類表(table1):
idtitle1電器
2服裝2、 二級分類表(table2):
idtitle
parent
11電視112
冰箱113空調114
**215兒童
23、 **分類表(table3):
idtitle
parent1
parent2
111櫃式112
112窗式112
113上衣214
在上面表的設計中,每層儲存上級id欄位,在**分類表中,更儲存了所有上級分類(只保留直接上級即可),可能不符合正規化,但這樣可以方便於資料庫訪問;表中id字段值做了特別處理,是為了顯而易見,實際當然不是這樣的。
在多表模式下,每個分類節點都處在相應級別的表中,分類節點的增加、更新、刪除操作都很方便,刪除時需要先刪除下級表中相關資訊。
例一, 在「**」分類節點下,增加乙個新的分類節點「長褲」。
insert into table3(id,title,parent1,parent2) values(114,」長褲」,2,14)
例二, 刪除「**」節點:
a, 先刪除「**」節點的下級節點:
delete from table3 where parent2=14
b,再刪除「**」節點:
delete from table3 where id=114
查詢操作根據需要有不同的複雜度,經常要橫跨多表,不甚方便。
例三, 查詢獲取「窗式」節點的路徑:
select title from table3 where id=112 /*查詢本層*/
union
select title from table2 where id=(select parent2 from table3 where id=112) /*上層*/
union
select title from table1 where id=(select parent1 from table3 where id=112)/*再上層*/
例四, 遍歷並列印所有分類樹:
db db=new db();
datatable table1=db.rundatatable("select * from table1",commandtype.text); //獲取一級分類
for(int i=0;i< p>
datarow row1=table1.rows[i];
console.writeline(row1["title"].tostring()+" ");
string sql="select * from table2 where parent="+row1["id"].tostring();
datatable table2=db.rundatatable(sql,commandtype.text);//獲取二級分類
for(int j=0; j< p>
datarow row2=table2.rows[j];
console.writeline("----"+row2["title"].tostring()+" ");
sql="select * from table3 where parent2="+row2["id"].tostring();
datatable table3=db.rundatatable(sql,commandtype.text);//獲取**分類
for(int k=0;k< p>
console.writeline("--------"+table3.rows[k]["title"].tostring()+" ");}}
}可以看到,在多表模式下,查詢操作經常要掃瞄所有表,效率確實不高,同時隨著層次的增加,查詢複雜性也成倍增長,所以多表模式只能用於資料層次固定且層次很少的場合,當然如果只有兩層,卻是首選。
二、鄰接表模式:
鄰接表模式是使用最頻繁的層次資料到關係表的轉換方法,有資料結構基礎的朋友,首先會想到這種方法,與多表方式不同,鄰接表模式,把層次資料平面化到一張表中,而在每個分類節點中儲存乙個父節點的資訊,根節點的父節點表示為空。如圖
商品分類表(table1):
parent
title
商品商品
電器商品
服裝電器
電視電器
冰箱電器
空調服裝
**服裝
兒童冰箱
櫃式冰箱
窗式**
上衣在表中parent欄位直接使用父節點的title值,這不是乙個好的設計,應該使用資料標識表示較好,如此是因為這樣比較容易看明白。
實際應用中,也可增加乙個字段表示分類節在所在的層次。這樣可是簡化一些操作,如果合理使用索引也能提高訪問效率。
下面看一些基本訪問操作。
例一、在「**」節點下增加乙個新分類「長褲」:
insert into table1(parent,title) values("成","長褲")
例二、獲取某一節點的子樹:
在鄰接表訪問操作中,經常要用到遞迴方法,可以使用資料庫的儲存過程或函式實現,但儲存過程或函式中,遞迴呼叫一般有層數限制,比如sql server2000被限制在32層之內。在下面的例子中都用c#函式實現。
public void displaytree(string title) } 例
三、獲取某一節點的路徑:
public string nodepath(string title)
else
return path;
} 例四,刪除乙個分類節點:
public void deletetree(string title)
else
} }
鄰接表模式,直觀、簡明、操作簡單、容易理解,並且可以實現無限級分類,是使用最多也是比較好的一種方法,但是在資料操作時,通常需要使用「遞迴」呼叫,並反覆掃瞄資料庫表,效率不高,cpu占用很大,如果資料量很大,執行會很慢,對於網路應用可能會引起超時。
上面先介紹兩種常用方法。其它在《層次資料的儲存與訪問(二)》中繼續**。
資料儲存與訪問 file
如果要開啟存放在 data data files目錄應用私有的檔案,可以使用activity提供openfileinput 方法。fileinputstream instream this.getcontext openfileinput itcast.txt log.i filetest read...
樹型控制項實現資料庫的訪問
本人意圖將資料庫中的內容加入樹型控制項中,通過建立資料庫,再與樹型控制項相連,實現資料庫的訪問。查詢結構清晰明了,操作方便。現將其方法闡述如下 1 建資料庫 建立access資料庫,資料庫結構和內容見程式包access檔案。2 建立單文件不基於資料庫支援的應用程式工程,檢視類繼承於cformview...
SQL Server樹型結構資料處理的儲存過程
我們在平常的系統開發中常常會遇到像無限級分類這樣的樹型結構資料,現提供乙個可用的資料庫儲存過程,可以完成樹型結構資料的排序。環境 windows7 sql server 2008 說明 下面 已經轉換成sql server2000的指令碼,處理效果如下,看sortname欄位結果,經過測試。建立樹型...