在ERP體系內,除了一般表格之外,就剩下樹狀結構了:部門組織、產品結構、銷售網路等等,都是透過標定上階與下階來描述『樹狀結構』。
樹狀資料,如果透過拆階儲存在資料表上,會有閱讀不易的狀況。這個可以透過一些程式技巧來組合列出,更可以將展出的資料暫時儲存,減少資料庫重複操作展開的工作,降低不必要的負擔。
此處描述的應該是一般人所熟悉的樹狀結構表:例如:本階節點001 / 父階節點002 講究的 (想讓每棵樹可以對樹枝、樹葉取相同名字的時候) 還可以將根結點另存 (例如欄位 000)
根結點 ed000
本階node ed001
父階node ed002
透過設定後,則識別為 root 以及各階的資料如下
階層 | 樹根 | 第一階 | 第二階 | 另一棵樹根 |
---|---|---|---|---|
根結點 ed000 | TREE-A | TREE-A | TREE-A | TREE-B |
本階node ed001 | TREE-A | brh-A1 | brh-A11 | TREE-B |
父階node ed002 | TREE-A | TREE-A | brh-A1 | TREE-B |
取得這樣的結構後,可以從表格中很容易選出樹根及各階節點,但是對於樹型,是難以理解的。
會利用 FGL可做 FUNCTION recursive呼叫的方式,逐層展開,進入抓取資料,例如:
#據點展開 使用 Genero 4.00語法
PUBLIC FUNCTION site_expand(lc_ed000 VARCHAR(20),lc_ed002 VARCHAR(20)) RETURNS ()
DEFINE ls_sql STRING
DEFINE lc_ed001 VARCHAR(20)
DEFINE li_cnt INT
LET ls_sql = "SELECT ed001 FROM 樹狀表 WHERE ed000=? AND ed002= ? "
#不存在陣列裡的, 填入才能往下展
DECLARE cs CURSOR FROM ls_sql
FORECAH cs USING lc_ed000,lc_ed002 INTO lc_ed001
SELECT COUNT(1) INTO li_cnt FROM 樹狀表 WHERE ed000=lc_ed000 AND ed002=lc_ed001
IF li_cnt > 0 THEN
CALL site_expand(lc_ed000,lc_ooed001) #重複呼叫自己 recursive
END IF
END FOREACH
END FUNCTION
這種方式,透過不斷的觸發查詢,進而將樹展開的做法 (也可以改成透過手動) 比較耗費資料庫與 FGL主機的資源,而且必須透過字串的組合,才能看出實際上的路徑樣式。程式寫法上也較為複雜。優點是所有邏輯能掌控在自己手中。
其實遞迴可以交給 ORACLE 做
#LEVEL是階層隔了幾層? path 就是展開後的路徑,父階欄位是 ed002,用反斜線分隔
LET ls_sql = "SELECT unique LEVEL, sys_connect_by_path(ed001,'/') as path ",
" FROM 樹狀表 ",
" WHERE ed001<>ed002 ", #如果本表中包含其他資料,利用此條件濾除
" START WITH ed001='TREE-A' ", #條件1:要做哪一棵根節點的條件
" CONNECT BY PRIOR ooed001 = ooed002 " #條件2:子與父之間的關係是哪一條,找出的條件
DECLARE cs CURSOR FROM ls_sql
ORACLE 9i之後,開始提供 sys_connect_by_path function,可以交由 ORACLE將整棵樹的結構展出來。
WHERE條件中,因為 ORACLE sys_connect_by_path function 無法接受父階=子階的資料,因此需要將上方此類資料進行排除,ORACLE才能進行資料檢索。
CONNECT 判斷的部分:摘錄 https://www.itread01.com/content/1549039892.html
提到:可做正樹 (從根到葉),還是倒樹(從葉到根), 關鍵在於connect by的條件.
正樹: 必須是 ‘父’= prior ‘子’
倒樹: 必須是 ‘子’= prior ‘父’
最終選出的資料就會是
3 /TREE-A/brh-A1/brh-A11
2 /TREE-A/brh-A1
2 /brh-A1/brh-A11
1 /TREE-A
1 /brh-A1
1 /brh-A11
透過這樣的方式,就會對樹狀的結構,比較清晰。
[更新註記] 10/07更新範例程式碼