1 前言
何謂遞歸,在程序編碼行業(yè)中,遞歸是經(jīng)常要聽到的名詞,但真正有使用遞歸程序解決用戶需求的程序編碼人員卻少之又少。
所謂遞歸,簡而言之就是應(yīng)用程序自身調(diào)用自身,以實(shí)現(xiàn)層次數(shù)據(jù)結(jié)構(gòu)的查詢和訪問。
2 遞歸程序的作用
我們有處理具有層次結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu)時(shí),往往需要使用遞歸的概念。
舉個(gè)實(shí)例:<以下我們均以BOM表作為實(shí)例進(jìn)行解釋,不再談及相對(duì)抽象的文字>
BOM表,在自稱為“ERP”的系統(tǒng)中,BOM采用的是有限定層次結(jié)構(gòu)的樹形結(jié)構(gòu),如:第一層表示成品、第二層表示半成品、第三層表示在第二層之下的半成品,如此推類,在層次限定的前提下,該程序通常沒有使用遞歸的概念進(jìn)行編程,BOM表的各個(gè)層級(jí)程序處理往往使用硬代碼編程,造成程序復(fù)雜,可移植性差,維護(hù)麻煩等缺點(diǎn)。
應(yīng)用遞歸的概念后,BOM表的層級(jí)可以無限,對(duì)BOM表的處理,如計(jì)算材料成本或原材料清單等,則可以使用簡潔的代碼來實(shí)現(xiàn)。
3 遞歸程序的特點(diǎn)
遞歸程序的共同特點(diǎn):
(1)代碼中必定包括一個(gè)循環(huán);
(2)循環(huán)中調(diào)用自身程序;
(3)循環(huán)的條件為遞歸終止的條件
如此構(gòu)成一個(gè)完整的遞歸程序
4 遞歸程序的應(yīng)用實(shí)例
--4.1 數(shù)據(jù)表結(jié)構(gòu)
--BOM表樣例,里面包含較為簡單的BOM層次結(jié)構(gòu)
Create Table Test_Bom (
ItemKey VarChar2(10) Not Null--產(chǎn)品(或材料)主鍵,關(guān)聯(lián)產(chǎn)品基本檔,在此不進(jìn)行具體描述。原應(yīng)為數(shù)值類型,在此以字符類型表示,以方便查看和說明。
,MaterialKey VarChar2(10) Not Null--半成品(或材料)主鍵,關(guān)聯(lián)產(chǎn)品基本檔,在此不進(jìn)行具體描述。原應(yīng)為數(shù)值類型,在此以字符類型表示,以方便查看和說明。
,Qty Number(6,2) Not Null--單位用量
,constraint PK_Test_Bom PRimary key (ItemKey,MaterialKey)
);
--4.2 測試數(shù)據(jù)
--A由A1和A2構(gòu)成
Delete From Test_Bom;
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a1','a',1);
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a2','a',2);
--A1由A11和A12構(gòu)成
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a11','a1',3);
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a12','a1',4);
--A11由A111和A112構(gòu)成
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a111','a11',5);
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a112','a11',6);
--A12由A121和A122以及A123構(gòu)成
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a121','a12',7);
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a122','a12',8);
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a123','a12',9);
--A2由A21和A22構(gòu)成
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a21','a2',10);
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a22','a2',11);
--A21由A212和A1構(gòu)成
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a212','a21',12);
Insert Into Test_Bom (MaterialKey, ItemKey,Qty) Values ('a1','a21',5);
Commit;
--由此看出真正需要購買的原材料是:a111,a112,a121,a122,a123,a22,a212
--4.3 需求
--要列出產(chǎn)品A的材料清單,以方便核算成本和請購材料。
--4.4 實(shí)現(xiàn)方法
--4.4.1 創(chuàng)建臨時(shí)表,用于存儲(chǔ)計(jì)算結(jié)果
--為方便查看,本例使用常規(guī)數(shù)據(jù)表,實(shí)際應(yīng)用過程中,應(yīng)使用臨時(shí)表,避免用戶之間的干擾
--create Global Temporary table Test_Bom_MaterialList_TP(
MaterialKey VarChar2(10) Not Null
-- ,Qty Number(10) Not Null
--)
-- On Commit PreServe Rows
--/
create table Test_Bom_MaterialList_TP(
MaterialKey VarChar2(10) Not Null
,Qty Number(10) Not Null
)
/
--4.4.2 創(chuàng)建程序包,用于計(jì)算原材料用量
CREATE OR REPLACE Procedure SP_EXPortMaterial
(P_ItemKey In Varchar2,P_Qty Number)
is
--=============================================
--創(chuàng)建存放游標(biāo)數(shù)據(jù)的記錄類型
--=============================================
type Material_rec is record(
ItemKey Test_Bom.ItemKey%type,
MaterialKey Test_Bom.MaterialKey%type,
Qty Test_Bom.Qty%Type);
--=============================================
--創(chuàng)建存放游標(biāo)記錄的記錄集對(duì)象
--=============================================
Material_Record Material_Rec;
--=============================================
--創(chuàng)建游標(biāo),游標(biāo)的記錄集數(shù)據(jù)類型為Material_Rec
--=============================================
Type Material_Cur is ref cursor Return Material_Rec;
--=============================================
--創(chuàng)建游標(biāo)對(duì)象
--=============================================
Material_Cursor Material_Cur;
L_IsNextLayer Numeric;--存放是否有下一層物料的變量
L_MaterialQty Numeric;--當(dāng)前物料的單位用量
begin
--=============================================
--打開游標(biāo),傳入數(shù)據(jù)
--=============================================
open Material_CurSor for
select ItemKey --主產(chǎn)品KEY
,MaterialKey --物料KEY
,Qty --物料標(biāo)準(zhǔn)用量
from Test_Bom
Where ItemKey=P_ItemKey;
--=============================================
--將數(shù)據(jù)傳入BOM_MaterialList_TP臨時(shí)數(shù)據(jù)表
--=============================================
--將游標(biāo)數(shù)據(jù)推入Material_Record記錄集對(duì)象/
Fetch Material_CurSor Into Material_Record;
While Material_Cursor%Found --判定游標(biāo)是否為空
Loop
--判定當(dāng)前物料編號(hào)是否有下一層物料
Select Count(0) Into L_IsNextLayer
From Test_Bom
Where ItemKey=Material_Record.MaterialKey;
If Not L_IsNextLayer=0 Then
--假如有下層物料,則執(zhí)行再調(diào)用SP_ExportMaterial<自身程序,遞歸點(diǎn)>
SP_ExportMaterial
(Material_Record.MaterialKey
,P_Qty*Material_Record.Qty);
Else
--將當(dāng)前游標(biāo)數(shù)據(jù)傳入Test_Bom_MaterialList_TP臨時(shí)數(shù)據(jù)表
Insert Into Test_Bom_MaterialList_TP
(MaterialKey,Qty)
Values(Material_Record.MaterialKey
,P_Qty*Material_Record.Qty);
--將游標(biāo)數(shù)據(jù)推入Material_Record記錄集對(duì)象
End if;
Fetch Material_CurSor Into Material_Record;
End Loop;
Commit;
end SP_ExportMaterial;
--4.5 測試
Delete From Test_Bom_MaterialList_TP; --刪除臨時(shí)表數(shù)據(jù)
SP_ExportMaterial('a1',1); --執(zhí)行計(jì)算程序
Select * from Test_Bom_MaterialList_TP;