Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Find A Parent on an Oracle "Tree" Table Based On A Compound Key

Status
Not open for further replies.

horatiog

Technical User
Oct 31, 2000
40
GB
Hi,

First off - don't blame me for the structure of this table ;-) I'm just trying to write a business view using this JDE table.

The table in question is the F0901 (Accounts Master) table in JD Edwards, which holds the entire account hierarchy.

What I need to do is to be able to start at a "leaf" on this table and "walk" back up the tree structure to the "root", using a recursive function, building a path between these two points as I go

I am having a brainstorm on exactly how to do this. My initial problem is that there is no self-referencing "foriegn key" in the table structure and the "key" that I have to use to find a parent is "compound".

The algorithm goes as follows:

For a child with a given business unit (GMMCU), account number (GMOBJ) and subsidiary account number (GMSUB), at a given level of the tree (GMLDA), the parent can be determined as the row:

- which has the same GMMCU as the child GMMCU
- which has a GMLDA one less than the child GMLDA
- which has the maximum (GMOBJ + GMSUB) that is less than or equal to the child (GMOBJ + SUB)

The description of the parent is held in GMDL01.

A "simplified" version of the code that I am currently using is:

SELECT
GM.GMDL01
FROM
F0901 GM
WHERE
GM.GMMCU = &Mcu
AND
GM.GMLDA = &ParentLevel
AND
(GM.GMOBJ || GM.GMSUB) =
( SELECT
MAX(GM1.GMOBJ || GM1.GMSUB)
FROM
F0901 GM1
WHERE
GM1.GMLDA = &ParentLevel
AND
GM1.GMMCU = &Mcu
AND
GM1.GMOBJ <= &Object
);

However, when running the recursive function, in which the above query is embedded, it is taking excessive amounts of time (30 minutes) to retrieve the paths for the approx 88,000 leaves that I need to do this for. I realise that there is an inefficiency in having "(GM.GMOBJ || GM.GMSUB)" on the LHS of the query, and I am sure there is way to do this using a correlated query, but I am stumped on how to do this with this compound key (MCU, OBJ & SUB)

Can anyone enlighten me - many thanks for any help you can provide.

Regards,
Harry Haines
 
Harry,

I believe we can compose a hierarchical tree-walk for you. But to assist in providing a working answer, could you please help us help you by posting the raw and simplified materials we should have to reconstruct your problem? To do so, could you please construct for us, and post here in this thread, the folowing:
Code:
CREATE TABLE F0901 (with column definitions for just the expressions invoved in the tree walk.)

INSERT INTO F0901 values (sample values for the column definitions for the F0901 table.)

Please provide enough INSERT statements to represent at least two hierarchies that are multiple levels deep.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)
@ 17:18 (05Dec04) UTC (aka "GMT" and "Zulu"),
@ 10:18 (05Dec04) Mountain Time
 
Hi Mufasa,

Thanks for the offer of help. I have developed the following script that creates the base table, inserts some sample rows into it, creates the function and then runs three queries against that function to show you what I am after.

I have shown in my comments the expected results. Some of the data doesn't make "accounting sense",but you should get the general principle of what I am after.

Code:
CREATE TABLE "F0901" (
	"GMCO"		CHAR(5), 
	"GMAID"		CHAR(8)    NOT NULL, 
	"GMMCU"		CHAR(12), 
	"GMOBJ"		CHAR(6), 
	"GMSUB"		CHAR(8),
    	"GMANS"		CHAR(25), 
	"GMDL01"	CHAR(30), 
	"GMLDA"		CHAR(1), 
	"GMBPC"   	CHAR(3), 
	"GMPEC"		CHAR(1), 
	"GMBILL"	CHAR(1), 
	"GMCRCD"	CHAR(3),
    	"GMUM"		CHAR(2), 
	"GMR001"	CHAR(3), 
	"GMR002"	CHAR(3), 
	"GMR003"   	CHAR(3), 
	"GMR004"	CHAR(3), 
	"GMR005"	CHAR(3), 
	"GMR006"	CHAR(3),
    	"GMR007"	CHAR(3), 
	"GMR008"	CHAR(3), 
	"GMR009"	CHAR(3),
    	"GMR010"	CHAR(3), 
	"GMR011"	CHAR(3), 
	"GMR012"	CHAR(3),
    	"GMR013"	CHAR(3), 
	"GMR014"	CHAR(3), 
	"GMR015"	CHAR(3),
    	"GMR016"	CHAR(3), 
	"GMR017"	CHAR(3), 
	"GMR018"	CHAR(3),
    	"GMR019"	CHAR(3), 
	"GMR020"	CHAR(3), 
	"GMR021"	CHAR(10),
    	"GMR022"	CHAR(10), 
	"GMR023"	CHAR(10), 
	"GMOBJA"	CHAR(6),
    	"GMSUBA"	CHAR(8), 
	"GMWCMP"	CHAR(4), 
	"GMCCT"		CHAR(1), 
	"GMERC"   	CHAR(2), 
	"GMHTC"		CHAR(1), 
	"GMQLDA"	CHAR(1), 
	"GMCCC"		CHAR(1),
    	"GMFMOD"	CHAR(1), 
	"GMUSER"	CHAR(10), 
	"GMPID"		CHAR(10),
    	"GMJOBN"	CHAR(10), 
	"GMUPMJ"	NUMBER(6), 
	"GMUPMT"	NUMBER,
CONSTRAINT 
	"F0901_PK" PRIMARY KEY("GMAID")
)
PCTFREE 10 
PCTUSED 40 
INITRANS 1
MAXTRANS 255
STORAGE 
(	INITIAL 66088K 
	NEXT 16384K 
	MINEXTENTS 1 
	MAXEXTENTS 2147483645 
	PCTINCREASE 0 
	FREELISTS 1 
	FREELIST 
	GROUPS 1
);

COMMIT;

INSERT INTO F0901
VALUES
(
	'00002',
	'00230329',
	'D0002',
	'73550',
	'',
	'',
	'Depreciation',
	'5',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'JOYCBLA',
	'EP0006',
	'JDEPC06',
	'101149',
	'153825'
);

INSERT INTO F0901
VALUES
(
	'00002',
	'00230333',
	'D0002',
	'73570',
	'',
	'',
	'Depn of Plant + Equipmen',
	'6',
	'',
	'B',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'JOYCBLA',
	'EP0006',
	'JDEPC06',
	'101149',
	'153825'
);

INSERT INTO F0901
VALUES
(
	'00002',
	'00230336',
	'D0002',
	'73573',
	'',
	'',
	'Depn of Vehicles',
	'7',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'JOYCBLA',
	'EP0006',
	'JDEPC06',
	'101149',
	'153825'
);

INSERT INTO F0901
VALUES
(
	'00002',
	'00230294',
	'D0002',
	'73000',
	'',
	'',
	'Administrative Expenses',
	'4',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'JOYCBLA',
	'EP0006',
	'JDEPC06',
	'101149',
	'153825'
);

INSERT INTO F0901
VALUES
(
	'00002',
	'00230247',
	'D0002',
	'70000',
	'',
	'',
	'ADMINISTRATIVE EXPENSES',
	'3',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'JOYCBLA',
	'EP0006',
	'JDEPC06',
	'101149',
	'153825'
);

INSERT INTO F0901
VALUES
(
	'00002',
	'00319430',
	'D0002',
	'73574',
	'100',
	'',
	'Depn of Desktops',
	'8',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'JOYCBLA',
	'EP0006',
	'JDEPC06',
	'101155',
	'145636'
);

INSERT INTO F0901
VALUES
(
	'80300',
	'01680341',
	'8031020002',
	'20000',
	'',
	'',
	'CURRENT ASSETS',
	'3',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'jdeent1',
	'104327',
	'221814'
);

INSERT INTO F0901
VALUES
(
	'80300',
	'01680342',
	'8031020002',
	'20100',
	'',
	'',
	'Stocks and Work in Progres',
	'4',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'jdeent1',
	'104327',
	'221814'
);

INSERT INTO F0901
VALUES
(
	'80300',
	'01680343',
	'8031020002',
	'22000',
	'',
	'',
	'Land + Dev WIP - Resident',
	'5',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'jdeent1',
	'104327',
	'221814'
);

INSERT INTO F0901
VALUES
(
	'80300',
	'01680347',
	'8031020002',
	'22200',
	'',
	'',
	'Development WIP - Res',
	'6',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'jdeent1',
	'104327',
	'221814'
);

INSERT INTO F0901
VALUES
(
	'80300',
	'01680355',
	'8031020002',
	'22280',
	'',
	'',
	'Financial Adjustments',
	'7',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'jdeent1',
	'104327',
	'221814'
);

INSERT INTO F0901
VALUES
(
	'80300',
	'01680583',
	'8031020002',
	'22290',
	'9037',
	'',
	'Electric,
	IT+Security',
	'9',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'G',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'R519901',
	'jdeent1',
	'104338',
	'125735'
);

INSERT INTO F0901
VALUES
(
	'80300',
	'01680598',
	'8031020002',
	'22285',
	'9076',
	'',
	'Devt C of S (Contra)',
	'8',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'N',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'R519901',
	'jdeent1',
	'104338',
	'140658'
);

INSERT INTO F0901
VALUES
(
	'03002',
	'00430164',
	'C1002',
	'60000',
	'',
	'',
	'Cost of Sales LOD3',
	'3',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'MG-040433',
	'102156',
	'111102'
);

INSERT INTO F0901
VALUES
(	
	'03002',
	'00430165',
	'C1002',
	'60010',
	'',
	'',
	'Cost of Sales LOD 4',
	'4',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'MG-040433',
	'102156',
	'111102'
);

INSERT INTO F0901
VALUES
(
	'03002',
	'00430166',
	'C1002',
	'63000',
	'',
	'',
	'Cost Of Sales LOD 5',
	'5',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'MG-040433',
	'102156',
	'111102'
);

INSERT INTO F0901
VALUES
(
	'03002',
	'00430171',
	'C1002',
	'63400',
	'',
	'',
	'Subcontractors Total',
	'6',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'MG-040433',
	'102156',
	'111102'
);

INSERT INTO F0901
VALUES
(
	'03002',
	'00430172',
	'C1002',
	'63410',
	'',
	'',
	'Sub Contractor Domestic (NEW)',
	'7',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'MG-040433',
	'102156',
	'111102'
);

INSERT INTO F0901
VALUES
(
	'03002',
	'00430173',
	'C1002',
	'63411',
	'',
	'',
	'Labour CIS Subcont Domestic',
	'8',
	'',
	'N',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'MG-040433',
	'102156',
	'111102'
);

INSERT INTO F0901
VALUES
(
	'03002',
	'00430586',
	'C1002',
	'63412',
	'05I1',
	'',
	'CIS Non-taxable',
	'9',
	'',
	'',
	'',
	'',
	'',
	'',
	'410',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'',
	'D',
	'',
	'',
	'9',
	'N',
	'',
	'PAULBOG',
	'EP51091',
	'MG-040433',
	'102156',
	'111102'
);

COMMIT;

CREATE OR REPLACE FUNCTION account_hierarchy 
	(
		Mcu		IN	CHAR,
		Object		IN	CHAR,
		Level		IN	NUMBER,
		Hierarchy	IN	VARCHAR
	)
	RETURN VARCHAR
IS
	CurrentObject		CHAR(6);
	CurrentHierarchy	VARCHAR(4000);
BEGIN
	IF	Level < 3
	THEN
		RETURN TRIM(Hierarchy);
	END IF;

	SELECT
		TRIM(GM.GMDL01) || '|' || TRIM(Hierarchy),
		GM.GMOBJ
	INTO
		CurrentHierarchy,
		CurrentObject
	FROM
		F0901 GM
	WHERE
		GM.GMMCU = Mcu
		AND
		GM.GMLDA = Level
		AND
		(GM.GMOBJ || GM.GMSUB) =
			(	SELECT
					MAX(GM1.GMOBJ || GM1.GMSUB)
				FROM
					F0901 GM1
				WHERE
					GM1.GMLDA = Level
					AND
					GM1.GMMCU = Mcu
					AND
					GM1.GMOBJ <= Object
			);

	RETURN account_hierarchy(Mcu,CurrentObject,(Level-1),CurrentHierarchy);

EXCEPTION
	WHEN	TOO_MANY_ROWS
	THEN
        	RETURN ('*** INVALID HIERARCHY - Too Many Parents ****: ' || Hierarchy || '(' || Mcu || ',' || Object || ')');

	WHEN NO_DATA_FOUND
	THEN
        	RETURN ('*** INVALID HIERARCHY - No Parent ****: ' || Hierarchy || '(' || Mcu || ',' || Object || ')');
END;
/

SELECT account_hierarchy('8031020002','22290',9,'Electric,IT+Security') FROM DUAL;

/* Should return "CURRENT ASSETS|Stocks and Work in Progres|Land + Dev WIP - Resident|Development WIP - Res|Financial IT+Security|Electric,IT+Security" */

SELECT account_hierarchy('D0002','73574',8,'Depn of Desktops')  FROM DUAL;

/* Should return "ADMINISTRATIVE EXPENSES|Administrative Expenses|Depreciation|Depn of Plant + Equipmen|Depn of Vehicles|Depn of Desktops|Depn of Desktops" */

SELECT account_hierarchy('C1002','63412',9,'CIS Non-taxable')  FROM DUAL;

/* Should return "Cost of Sales LOD3|Cost of Sales LOD 4|Cost Of Sales LOD 5|Subcontractors Total|Sub Contractor Domestic (NEW)|Labour CIS Subcont Domestic|CIS Non-taxable|CIS Non-taxable" */

I hope this helps you to help me but if you want any more info, just ask. Once again - many thanks.

Regards,
Harry Haines.
 
Hi,

Anybody got any ideas on how I can make this function any faster? Many thanks for any help proferred.

Regards,
Harry Haines.
 
Harry,

I'm sorry for not getting back to you sooner.

When I suggested, "I believe we can compose a hierarchical tree-walk for you", I based my comment on the presumption that data (no matter how many columns) existed on your "child records" that also existed uniquely on your "parent records". Either my presumption was wrong, or I am not seeing the explicit linking data. If, in fact, you are lacking that type of a setup, then you are also lacking a true "information-based" hierarchy.

Could you please set me straight on your data?

If my worries are correct, and if you are looking for speed, efficiency, and flexibility in your hierarchy, then here is my suggestion to achieve the best of all worlds:

Take the Primary Key value of "parent" records and place the values in a column named (perhaps) "Parent_ID" on the "child" records.

You can either make the change/enhancement by hand or via script. Once you do that, I absolutely, positively guarantee that we can give you a single-SELECT method of producing highly efficient hierarchy tree walks for as many/few branches and levels as you wish.

Let us know if either a) I'm missing the explicit parent-child connections on each row or b) you are willing to make this one-column-addition leap of faith.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)
@ 18:17 (09Dec04) UTC (aka "GMT" and "Zulu"),
@ 11:17 (09Dec04) Mountain Time
 
Hi Mufasa,

Thanks for your reply.

The primary key on this table is GMAID. However, I don't THINK I can use this column to form a relationship between the two levels of the query and instead I have to use the unique composite key of GMMCU + GMOBJ + GMSUB.

The parent for any row in the table can be given as the row which:

- has the same GMMCU as the child GMMCU
and
- has a GMLDA one exactly less than the child GMLDA (ie.. GMLDA - 1)
and
- has the maximum (GMOBJ + GMSUB) that is less than or equal to the child (GMOBJ + SUB)

However, if you can enlighten me as to a way of using these columns in better way, it would be very much appreciated.

WRT your second idea, I think what you are suggesting is to add a self-referencing foreign key ("GMAID_PARENT" or somesuch) into the table. Unfortunately, the table forms part of a third party system and therefore I would definately not be allowed to do this. Nice thought though ;-)

Speak soon.

Regards,
Harry.
 
Harry,

Okay, I'll do some problem solving with this later today. Presently, I must go to a company Holiday party, so I hope you don't mind the postponement for a few hours.

[santa]Mufasa
(aka Dave of Sandy, Utah, USA)
@ 18:40 (09Dec04) UTC (aka "GMT" and "Zulu"),
@ 11:40 (09Dec04) Mountain Time
 
No worries. Enjoy your bash.

Hope to hear from you when you have a moment.

Thanks & regards,

Harry.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top