iT邦幫忙

2021 iThome 鐵人賽

0
Software Development

Genero Packages - 可接替4GL的LowCode商業語言系列 第 31

[FGL] 列出樹狀表所有節點路徑的思路與實作

在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

取得這樣的結構後,可以從表格中很容易選出樹根及各階節點,但是對於樹型,是難以理解的。

傳統的遞迴 recursive 作法

會利用 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 function: sys_connect_by_path

其實遞迴可以交給 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更新範例程式碼


上一篇
[Genero 4.00] 新上線,語言動態化(VAR)+自適應畫面
下一篇
[FLM] 比較5.19 / 5.20 / 6.00 三者不同處
系列文
Genero Packages - 可接替4GL的LowCode商業語言32

尚未有邦友留言

立即登入留言