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.
| Author |
Topic |
|
timgaunt
Posting Yak Master
115 Posts |
Posted - 2005-09-07 : 13:19:28
|
| Hi,I know I've asked the same question in the articles discussion forum but I wonder if it was the wrong place :) (sorry if its not)I've been using Corey's Tree Hierachy code (http://www.seventhnight.com/treestructs.asp) but have got a little stuck extracing the data.Basically we're trying to achieve two main outputs, the first being a breadcrumb navigation system to thier current location ie: England > West Midlands > DudleyThe second is a list of areas within an area ie (for Dudley):- Brierley Hill- Merry HillThe data we're using looks like this (PlaceID, ParentID, PlaceName):1 0 England2 1 West Midlands3 2 Dudley4 3 Brierley Hill5 3 Merry HillIs the method described by Corey the best to achieve this? I think the issue is that I don't need SQL to concatenate the strings as I can manage that in ASP.NET but its how to extract each Parent as a seperate record...Cheers.Tim |
|
|
Kristen
Test
22859 Posts |
Posted - 2005-09-07 : 14:16:33
|
| Just to make sure I've understood:Given "Dudley" [level 2] you want to find the ancestors ("West Midlands", and then "England" - [Level 1 and Level 0]) and All Children ("Brierley Hill" and "Merry Hill") [Level 3]?Kristen |
 |
|
|
timgaunt
Posting Yak Master
115 Posts |
Posted - 2005-09-07 : 14:16:58
|
| Ok, after a little more playing I've worked out how to get the info in the way required but is it correct or is it overly server intensive, basically what I'm doing after it builds the paths table is selecting the record from the paths table with the NodeID (PlaceID) we're interested in and then splitting its path and joining that to all the name at the end, is there a better way of doing that?Here's my code which replaces Corey's final select statement:Declare @nodePath nvarchar(1000)SELECT @nodePath = SUBSTRING(path, 1 , LEN(path)-1) --Trim off the final ;FROM @pathsWHERE PlaceID = @PlaceID --Passed into the SProc (its an INT)CREATE TABLE #List(Item varchar(8000)) -- Create a temporary tableDECLARE @Delimiter char(1)DECLARE @Item Varchar(8000)SET @Delimiter = ';' -- delimiter that separates itemsWHILE CHARINDEX(@Delimiter, @nodePath,0) <> 0BEGINSELECT @Item=RTRIM(LTRIM(SUBSTRING(@nodePath,1,CHARINDEX(@Delimiter, @nodePath,0)-1))), @nodePath=RTRIM(LTRIM(SUBSTRING(@nodePath,CHARINDEX(@Delimiter, @nodePath,0)+1,LEN(@nodePath)))) IF LEN(@nodePath) > 0 INSERT INTO #List SELECT @ItemENDIF LEN(@nodePath) > 0 INSERT INTO #List SELECT @nodePath -- Put the last item in/* Select all the new ID's and join to get the names etc */SELECT *FROM #List As A INNER JOIN @tree As B ON CAST(A.Item As int) = B.PlaceIDDROP TABLE #List |
 |
|
|
timgaunt
Posting Yak Master
115 Posts |
Posted - 2005-09-07 : 14:18:21
|
| Hi Kristen,Yeah thats basically it but its two seperate datasets, so one will be to find the parents and the other to find the children, I've sorted the children as thats in Corey's article but its just the ancestors that I'm having problems with :).The reason I was questioning the children was because I'm wondering if this is overkill for our requirements -in this example we won't have many parent nodes to a single child node.Tim |
 |
|
|
Kristen
Test
22859 Posts |
Posted - 2005-09-07 : 14:30:58
|
| I haven't reviewed the article, but we do two things1) Store a "path", in each record, of all the ancestors (i.e. a delimited, or fixed length, list of IDs or somesuch)2) Store a Sequence Number so that an ORDER BY will give us the whole tree (or some part of it) in "Tree Order"But that may be out of context without me having read the article.Krsten |
 |
|
|
Seventhnight
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2005-09-07 : 16:42:20
|
sorry... didn't read that it had moved...:here's my post from yonderquote: Well I'll be darned!!@nodes is a reference to a distinct list of nodes. In a multiparent environment, node definition must exist in a table seperate from node relationships. In a single parent environment, the relationship can be located on the node definition record.Since your table contains the relationship as well as the definition, you can replace @nodes with your table name...Here's my shot:Declare @tree table( cNodeId int, pNodeId int, name varchar(50), processed bit default(0))Insert Into @treeSelect 1, 0, 'England', 0 Union AllSelect 2, 1, 'West Midlands', 0 Union AllSelect 3, 2, 'Dudley', 0 Union AllSelect 4, 3, 'Brierley Hill', 0 Union AllSelect 5, 3, 'Merry Hill', 0Declare @pad nvarchar(100),@lastCnt intSet @Pad = '0000'Declare @paths table (path nvarchar(1000), pNodeId int, cNodeId int) Insert Into @pathsSelect path=right(@pad + convert(nvarchar,pNodeId),len(@pad))+';' + right(@pad + convert(nvarchar,cNodeId),len(@pad))+';', pNodeId, cNodeIdFrom @Tree where pNodeId=0 Update ASet Processed = 1From @Tree as AInner Join @paths as BOn A.pNodeId = B.pNodeIdand A.cNodeId = B.cNodeIdWhile exists(Select * From @tree Where Processed = 0) Begin Insert Into @paths Select path=path + case when B.cNodeId is not null then right(@pad+convert(nvarchar,B.cNodeId),len(@pad))+';' else '' end, B.pNodeId, B.cNodeId From @Paths as A Left Join @Tree as B On A.cNodeId = B.pNodeId Where B.Processed = 0 Update A Set Processed = 1 From @Tree as A Inner Join @paths as B On A.pNodeId = B.pNodeId and A.cNodeId = B.cNodeId Where A.Processed = 0End Select * From @pathsDeclare @nodeId intSet @nodeId = 3Select distinct pNodeId = B.cNodeId, B.name, level = (charindex(right(@pad+convert(nvarchar,B.cNodeId),len(@pad))+';',A.Path)-1)/(len(@pad)+1)From @paths as A, @Tree as BWhere A.path like '%'+right(@pad+convert(nvarchar,B.cNodeId),len(@pad))+';%'+right(@pad+convert(nvarchar,@NodeId),len(@pad))+';%'Select distinct A.cNodeId, B.Name, level = (charindex(right(@pad+convert(nvarchar,B.cNodeId),len(@pad))+';',A.Path)-1)/(len(@pad)+1)From @paths as AInner Join @tree as BOn A.cNodeId = B.cNodeIdWhere A.path like '%' + right(@pad + convert(nvarchar,@NodeId),len(@pad))+';%'and A.cNodeId <> @NodeId I'm not sure exactly what you were going for with the children section... I would really just suggest the path table minus the current path... but let me know where you're at!?
Corey Co-worker on The Wizard of Oz "...those three midgets that came out and danced, the freaked me out when I was little. But they are ok now." |
 |
|
|
timgaunt
Posting Yak Master
115 Posts |
Posted - 2005-09-08 : 05:27:20
|
| Hi Corey,thanks for your reply, I decided to move it here as although you should be crowned the King of Hierachial Tree data I felt it was unfair to expect you to reply.Thanks also to Kristen for the response but sadly I can't use order by because it also brings through other records that will distort the info and the entire path is stored in the table but didn't get me very far.In regards your code Corey, it does indeed produce the correct results but its incredibly slow (10seconds for 1086 records) which is odd because the path's code runs fine, when I use the code that I posted a couple of posts ago only takes 1/2seconds so I guess its the way to go or have I missed som glaring error?Re: the children, thanks I sorted that, not too sure what I was asking now lol, I think it was just so you had my entire problem lol.Many thanks again.Tim |
 |
|
|
Seventhnight
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2005-09-08 : 08:27:11
|
I'm glad you got it figured out! I have a different query for the parents, so if you get a chance would you test it out and see if it does better than the 10 seconds for 1086 rows??replace:Select distinct pNodeId = B.cNodeId, B.name, level = (charindex(right(@pad+convert(nvarchar,B.cNodeId),len(@pad))+';',A.Path)-1)/(len(@pad)+1)From @paths as A, @Tree as BWhere A.path like '%'+right(@pad+convert(nvarchar,B.cNodeId),len(@pad))+';%'+right(@pad+convert(nvarchar,@NodeId),len(@pad))+';%'with:Select distinct pNodeId = C.cNodeId, C.name, Level = (len(A.Path)/(len(@pad)+1))-1From @paths as AInner Join (Select path from @paths Where cNodeId=@NodeId) BOn B.path like A.path+'%'Inner Join @Tree as COn A.cNodeId = C.cNodeIdWhere C.cNodeId<>@NodeId Corey Co-worker on The Wizard of Oz "...those three midgets that came out and danced, the freaked me out when I was little. But they are ok now." |
 |
|
|
timgaunt
Posting Yak Master
115 Posts |
Posted - 2005-09-08 : 10:03:39
|
| Super Corey thats much better and I much prefer yours thanks for that. You can rightly claim your Hierachy Crown again haha. The only change I made was remove "Where C.cNodeId<>@NodeId" so I could also have the most current node for the breadcrumb (can't have these people getting lost now can we haha)Thanks againTim |
 |
|
|
Seventhnight
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2005-09-08 : 10:24:59
|
Why thank you ...and you're welcome!! Corey Co-worker on The Wizard of Oz "...those three midgets that came out and danced, the freaked me out when I was little. But they are ok now." |
 |
|
|
|
|
|
|
|