Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Account Structure Hierachies

Author  Topic 

kishv
Starting Member

3 Posts

Posted - 2004-05-29 : 18:44:47
Hi,

Can anyone help?

I have some data from an accounting system. The data comes out as below:-

CODE LEVEL NAME
100000 1 Account1
110000 3 ACCOUNT2
112000 5 ACCOUNT3
113000 5 ACCOUNT4
120000 6 ACCOUNT5
119000 5 ACCOUNT6

Basically the end result should be as follows

- Account1
-- ACCOUNT2
--- ACCOUNT3
--- ACCOUNT4
---- ACCOUNT5
----- ACCOUNT6

I am trying to use the Cursur approach in T-SQL to loop through and build the hierachy based on the level column. I have another table that I want to populate based on the input table.

Destination table looks like this.

ID Parent CHILD

Any idea how I can take the source data and present in the format that populates the destination table.

Would like some sample code to get me started.

Thanks

Kristen
Test

22859 Posts

Posted - 2004-05-30 : 07:41:14
To get the "---" prefix you could just do

SELECT REPLICATE('-', LEVEL)

Note that your proposed PARENT / CHILD table doesn't tell you the sequence of the children (maybe you are happy to use the PK of the original table as a tie-break?)

I'm not quite sure how your current LEVEL helps - I don't see how you know that Code=120000 (ACCOUNT5) is a child of 113000 (ACCOUNT4) rather than 112000 (ACCOUNT3) or 119000 (ACCOUNT6) as all three are the same level, and thus potential parents - in the absence of some extra information.

Given knowledge of what the PARENT and immediately elder SIBBLING are, and assuming no more than 999 LEVELS and 999 SIBBLINGS for any given PARENT, the following code will construct LEVEL [i.e. Number of ancestors that exist back to the Root], SEQUENCE [i.e. Eldest to Youngest sibbling sequence] and a PATH [concatentation of all IDs of Parents/GrandParents etc.]

Note that duplicate SIBBLING references would yeild indeterminate SIBBLING SEQUENCE ...


-- Note that if Sibbling pointers are NOT unique the sequence generated is indeterminate

DROP TABLE #MyTempTable
GO

CREATE TABLE #MyTempTable
(
[T_MyID] int,
[T_MyParent] int,
[T_MySibbling] int,
[T_MyLevel] int,
[T_MySequence] int,
[T_MyPath] varchar(7000)
)

-- Select all relevant original data into temporary table
INSERT INTO #MyTempTable
SELECT
[T_MyID] = MyID,
[T_MyParent] = MyParent,
[T_MySibbling] = MySibbling,
[T_MyLevel] = NULL,
[T_MySequence] = NULL,
[T_MyPath] = NULL
FROM dbo.MyTable

DECLARE @intLoop int,
@intRowCount int

-- Set LEVEL and SEQUENCE for Root Node
UPDATE U
SET [T_MyLevel] = 0,
[T_MySequence] = 0,
[T_MyPath] = '000000' -- Max is 999 Levels and 999 Siblings, thus 6-digits
FROM #MyTempTable U
WHERE T_MyParent IS NULL
AND T_MySibbling IS NULL


-- Set SEQUENCE on all Eldest Siblings
UPDATE U
SET [T_MySequence] = 0
FROM #MyTempTable U
WHERE T_MySibbling IS NULL

SELECT @intLoop = 0,
@intRowCount = 1 -- Force to run at least once

-- Set SEQUENCE on all rows
WHILE (@intRowCount >= 1)
BEGIN
IF @intLoop >= 999 RAISERROR ('Maximum Sibbling Sequence exceeded', 16, 1)

-- Set all next-younger sibblings to the next-higher sequence
UPDATE C
SET [T_MySequence] = @intLoop + 1
FROM #MyTempTable C
JOIN #MyTempTable P
ON P.T_MyID = C.T_MySibbling
WHERE C.T_MySequence IS NULL -- Not-yet-done children ...
AND P.T_MySequence IS NOT NULL -- ... of already-done parents
AND P.T_MySequence = @intLoop
SELECT @intRowCount = @@ROWCOUNT

-- SELECT [Level] = @intLoop, [Count] = @intRowCount -- Debug

SELECT @intLoop = @intLoop + 1 -- Proceed to next level
END

SELECT @intLoop = 0,
@intRowCount = 1 -- Force to run at least once

-- Set LEVEL on all rows
WHILE (@intRowCount >= 1)
BEGIN
IF @intLoop >= 999 RAISERROR ('Maximum Child Level exceeded', 16, 1)

-- Set all children to the next-higher level
UPDATE C
SET T_MyLevel = @intLoop + 1,
T_MyPath = P.T_MyPath + '/'
+ RIGHT('000'+CONVERT(varchar(20), @intLoop+1), 3)
+ RIGHT('000'+CONVERT(varchar(20), C.T_MySequence), 3)
FROM #MyTempTable C
JOIN #MyTempTable P
ON P.T_MyID = C.T_MyParent
WHERE C.T_MyLevel IS NULL -- Not-yet-done children ...
AND P.T_MyLevel IS NOT NULL -- ... of already-done parents
AND P.T_MyLevel = @intLoop
SELECT @intRowCount = @@ROWCOUNT

-- SELECT [Level] = @intLoop, [Count] = @intRowCount -- Debug

SELECT @intLoop = @intLoop + 1 -- Proceed to next level
END


-- Set the Level, Sequence and Path on the original table
UPDATE U
SET MyLevel = T.T_MyLevel,
MySequence = T.T_MySequence,
MyPath = T.T_MyPath
FROM #MyTempTable T
JOIN dbo.MyTable U
ON U.MyID = T.T_MyID

This approach is fine if you only want to add new records at the END of a limb. If you want to INSERT in the middle of a limb, or if you want to be able to MOVE nodes to different parts of the tree, then you need something that either 1) renumbers the tree every time :-( or 2) leaves gaps for insertions and renumbers parts of the tree when they are full.

Kristen
Go to Top of Page

nr
SQLTeam MVY

12543 Posts

Posted - 2004-05-30 : 08:20:28
Have a look at
http://www.nigelrivett.net/RetrieveTreeHierarchy.html

==========================================
Cursors are useful if you don't know sql.
DTS can be used in a similar way.
Beer is not cold and it isn't fizzy.
Go to Top of Page
   

- Advertisement -