一種能跨數(shù)據(jù)庫的樹形數(shù)據(jù)表格設(shè)計(jì)
在數(shù)據(jù)表的設(shè)計(jì)中,對(duì)于樹形的表格數(shù)據(jù),處理起來時(shí)比較棘手的,個(gè)人經(jīng)歷過sql server,oracle,mysql,發(fā)現(xiàn)對(duì)于樹形的表格數(shù)據(jù)處理都不同。通常的屬性表格設(shè)計(jì)時(shí)我們會(huì)這樣設(shè)計(jì):
id int ,
nodename varchar(50),
parentid int
)
雖然主流的ORM框架能處理數(shù)據(jù)庫廠商sql語法的差異,但是對(duì)于樹形數(shù)據(jù)還是缺乏統(tǒng)一的支持。所以有人設(shè)計(jì)了一個(gè)這樣的表結(jié)構(gòu):
2 (
3 NODELEVEL INTEGER not null,
4 LEVELCODE VARCHAR2(500) not null,
5 PARENTNODE VARCHAR2(500),
6 NODENAME VARCHAR2(200)
7 /*其他字段略*/
8 )
- nodelevel是樹的深度,1,2,3...
- levelcode這個(gè)字段格式是這樣的,我們可以假定每級(jí)節(jié)點(diǎn)的數(shù)量是有上限的,可以根據(jù)需要約定比如我們限定每個(gè)節(jié)點(diǎn)的最多是99999個(gè)子節(jié)點(diǎn)。這樣。levelcode 的第一個(gè)節(jié)點(diǎn)可以levelcode編號(hào)為"00001",其相鄰節(jié)點(diǎn)為"00002",他的第一個(gè)子節(jié)點(diǎn)為"0000100001",以此類推,可以為每個(gè)節(jié)點(diǎn)一個(gè)唯一編號(hào)。
- parentnode就是父節(jié)點(diǎn)的levelcode
- nodename是節(jié)點(diǎn)名稱
這樣的設(shè)計(jì)后。我們給出一個(gè)實(shí)例查詢:
這樣查詢的結(jié)果形如:
NODELEVEL | NODENAME | LEVELCODE | PARENTNODE |
1 | 一級(jí)測(cè)試節(jié)點(diǎn)1 | 00001 | |
2 | 二級(jí)測(cè)試節(jié)點(diǎn)1 | 0000100001 | 00001 |
3 | sdfasfasfad | 000010000100001 | 0000100001 |
2 | 二級(jí)測(cè)試節(jié)點(diǎn)2 | 0000100002 | 00001 |
2 | 二級(jí)測(cè)試節(jié)點(diǎn)3 | 0000100003 | 00001 |
2 | 二級(jí)測(cè)試節(jié)點(diǎn)5 | 0000100005 | 00001 |
2 | asdfgh | 0000100007 | 00001 |
1 | 一級(jí)測(cè)試節(jié)點(diǎn)2 | 00002 | |
2 | 二級(jí)測(cè)試節(jié)點(diǎn)2 | 0000200001 | 00002 |
3 | fasdfasfsaf | 000020000100001 | 0000200001 |
2 | 二級(jí)測(cè)試gg4 | 0000200002 | 00002 |
3 | dfasfasfas | 000020000200001 | 0000200002 |
3 | fgh | 000020000200001 | 0000200002 |
4 | fdsafdas | 00002000020000100001 | 000020000200001 |
4 | dfasfsafsda | 00002000020000100001 | 000020000200001 |
5 | fadsfasfsa | 0000200002000010000100001 | 00002000020000100001 |
5 | fdasfdasfasdf | 0000200002000010000100001 | 00002000020000100001 |
3 | dsafasfasdf | 000020000300001 | 0000200003 |
1 | 測(cè)試深度節(jié)點(diǎn)1 | 10001 | |
2 | 測(cè)試深度節(jié)點(diǎn)10 | 1000100000 | 10001 |
3 | 測(cè)試深度節(jié)點(diǎn)100 | 100010000000000 | 1000100000 |
4 | 測(cè)試深度節(jié)點(diǎn)1000 | 10001000000000000000 | 100010000000000 |
5 | 測(cè)試深度節(jié)點(diǎn)10000 | 1000100000000000000000000 | 10001000000000000000 |
1 | 測(cè)試深度節(jié)點(diǎn)2 | 10002 | |
2 | 測(cè)試深度節(jié)點(diǎn)20 | 1000200000 | 10002 |
3 | 測(cè)試深度節(jié)點(diǎn)200 | 100020000000000 | 1000200000 |
4 | 測(cè)試深度節(jié)點(diǎn)2000 | 10002000000000000000 | 100020000000000 |
5 | 測(cè)試深度節(jié)點(diǎn)20000 | 1000200000000000000000000 | 10002000000000000000 |
6 | qwerfga | 100020000000000000000000000001 | 1000200000000000000000000 |
2 | sdfg | 1000200001 | 10002 |
3 | safsdfsadfaaa | 100020000100001 | 1000200001 |
他是樹的深度遍歷結(jié)果,這也就是這樣設(shè)計(jì)的最大的好處。
對(duì)于新增樹節(jié)點(diǎn)時(shí)需要多做一步就是計(jì)算levelcode,比如增加同級(jí)節(jié)點(diǎn)時(shí)需要找到同級(jí)節(jié)點(diǎn)的最后一個(gè)節(jié)點(diǎn)。然后將levelcode最后一節(jié)+1。對(duì)于新增子節(jié)點(diǎn)需要找到最大levelcode的子節(jié)點(diǎn)然后+1。
刪除也比較方便,如需要?jiǎng)h除一個(gè)節(jié)點(diǎn)以及其所有的子節(jié)點(diǎn),可以
需要獲取樹的廣度遍歷結(jié)果可以直接用nodelevel排序。
這樣的設(shè)計(jì)帶來的好處是在各種數(shù)據(jù)庫上都可以用。不會(huì)因?yàn)閿?shù)據(jù)庫不同獲取樹的遍歷結(jié)果需要寫不同的sql。
當(dāng)然,問題在于levelcode的計(jì)算會(huì)導(dǎo)致同級(jí)節(jié)點(diǎn)的排序不好實(shí)現(xiàn)。要獲取遍歷結(jié)果,通常是按照levelcode排序,由于計(jì)算levelcode是根據(jù)新增的先后順序,所以同級(jí)排序就留給大家思考了。
posted on 2010-10-25 11:20 衡鋒 閱讀(2576) 評(píng)論(4) 編輯 收藏 所屬分類: Oracle