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 |
|
brokedowngames
Starting Member
5 Posts |
Posted - 2011-07-28 : 19:34:54
|
What I'm trying to do is to create a sorted hierarchy from a single table. The table includes Ids, a parentId, and a sort value among other columns. Basically, I start with the highesthierarchy and grab those values and sort them. Then for each of those I add it to finalized list and grab the children, sort them and then do the same thing for their children.Some sample data from MyTable:ID SortValue ParentId ElementType5 2 0 11 5 5 22 6 5 28 7 1 34 6 2 3 After all is said and done @Final should contain the following:Seq ID1 52 13 84 25 4 As you can see each level of hierarchy has its own micro-sorting.There has to be a better way of doing this. Coming from a C++/C# background, I can't help but think in terms of iteration, but I know this strategy is frowned up in SQL.DECLARE @MasterList Table( id int, sortvalue int, parentid int, ElementType int)DECLARE @Level1 Table( seq int identity(1, 1), id int)DECLARE @Level2 Table( seq int identity(1, 1), id int)DECLARE @Level3 Table( seq int identity(1, 1), id int)DECLARE @Final Table( seq int identity(1, 1), id int)insert into @MasterListselectid,sortvalue,ParentId,ElementTypefrom MyTableinsert into @Level1select idfrom @MasterListwhere ElementType = 1order by sortvaluewhile exists(select top 1 * from @Level1)begin declare @level1Id int select top 1 @level1Id = id from @Level1 insert into @Final select @level1Id delete @Level2 insert into @Level2 select id from @MasterList e where e.parentid = @level1Id order by sortvalue while exists(select top 1 * from @Level2) begin declare @level2Id int select top 1 @level2Id = id from @Level2 insert into @Final select @level2Id delete @Level3 insert into @Level3 select id from @MasterList e where e.parentid = @level2Id order by sortvalue while exists(select top 1 * from @Level3) begin declare @level3Id int select top 1 @level3Id = id from @Level3 insert into @Final select @level3Id delete from @Level3 where id = @level3Id end delete from @Level2 where id = @level2Id end delete from @Level1 where id = @level1Idendselect * from @Final |
|
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-07-28 : 22:41:56
|
[code]; with rcte as( select lvl = 1, id, sort = convert(varchar(max), '1') from MyTable where Parentid = 0 union all select lvl = r.lvl + 1, id = t.id, sort = convert(varchar(max), r.sort) + convert(varchar(max), row_number() over (order by t.sortvalue)) from rcte r inner join MyTable t on r.id = t.Parentid)select seq = row_number() over (order by sort), *from rcteorder by seq[/code]note : the lvl is only to show the hierarchy of the id KH[spoiler]Time is always against us[/spoiler] |
 |
|
|
brokedowngames
Starting Member
5 Posts |
Posted - 2011-07-28 : 23:06:09
|
quote: Originally posted by khtan
; with rcte as( select lvl = 1, id, sort = convert(varchar(max), '1') from MyTable where Parentid = 0 union all select lvl = r.lvl + 1, id = t.id, sort = convert(varchar(max), r.sort) + convert(varchar(max), row_number() over (order by t.sortvalue)) from rcte r inner join MyTable t on r.id = t.Parentid)select seq = row_number() over (order by sort), *from rcteorder by seq note : the lvl is only to show the hierarchy of the id KH[spoiler]Time is always against us[/spoiler]
Thanks for your reply.I thought maybe a CTE was the way to go. Unfortunately this isn't quite what I need because this doesn't intertwine the results. This gets everything at level 1, sorts, then everything at level 2 sorts, etc.What I require is to sort level 1 and after each level 1 entry have sorted child level 2 entries and after each level 2 entry have sorted level 3 entries.So what it should look like is something like this:Level1 Level2 Level3 Level3 Level3 Level2 Level3 Level3Level1 Level2 Level3 Level3 Level2 Level3 Where the Level1 are sorted, Level2 are sorted under their respective Level1 parent and Level3 are sorted under their respective Level2. Sorry if my original example wasn't clear. Maybe this makes more sense. I still think maybe there's a way to make a CTE for this, but given my limited SQL knowledge it eludes me.Thanks. |
 |
|
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-07-28 : 23:09:44
|
did you try the query ? it does not give the required result ? KH[spoiler]Time is always against us[/spoiler] |
 |
|
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-07-28 : 23:40:58
|
on 2nd look ... the sorting is bit tricky, let me take a look at it again. KH[spoiler]Time is always against us[/spoiler] |
 |
|
|
brokedowngames
Starting Member
5 Posts |
Posted - 2011-07-28 : 23:42:38
|
quote: Originally posted by khtan did you try the query ? it does not give the required result ? KH[spoiler]Time is always against us[/spoiler]
Ah, it actually is very close; I just didn't recognize immediately what was going on. I see it's doing a string comparison so that the hierarchy would be 1 11 111 112 2 21 etc which works well. The problem is if you have more than 9 rows for a single grouping. Then you end up with something like:1 11 110 where the 110 is actually a the 10th level 2 in the level 1 grouping. I guess the way to fix this would be to extract out it's primary sort and have it stored as an integer or something like that.Thanks again. |
 |
|
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-07-28 : 23:48:43
|
ya ... close but not closed enough still have flaws on the sorting . . KH[spoiler]Time is always against us[/spoiler] |
 |
|
|
brokedowngames
Starting Member
5 Posts |
Posted - 2011-07-29 : 00:06:26
|
quote: Originally posted by khtan ya ... close but not closed enough still have flaws on the sorting . . KH[spoiler]Time is always against us[/spoiler]
Something that is giving slightly better results although it looks tacky is:select lvl = r.lvl + 1, id = t.id, sort = convert(varchar(max), convert(int, r.sort) * 10 + row_number() over (order by t.sortvalue)) This still wouldn't work if there were more than 99 rows on each, but I guess one I can find a number that is high enough to use this if I have to. Is there maybe a way to integrate rowcount into this to get a multiplier? |
 |
|
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2011-07-29 : 02:43:25
|
[code]; with rcte as( select lvl = 1, id, root = id, sort = convert(varchar(max), '00001') from MyTable where Parentid = 0 union all select lvl = r.lvl + 1, id = t.id, root = r.root, sort = convert(varchar(max), r.sort) + right('00000' + convert(varchar(max), row_number() over (order by t.sortvalue)), 5) from rcte r inner join MyTable t on r.id = t.Parentid)select seq = row_number() over (order by sort), *from rcteorder by root, seq[/code] KH[spoiler]Time is always against us[/spoiler] |
 |
|
|
brokedowngames
Starting Member
5 Posts |
Posted - 2011-07-29 : 10:08:56
|
| Thanks for your help khtan. |
 |
|
|
|
|
|
|
|