I have what would seem to be a simple problem but the solutions I have tried to date have left me wanting in the execution areas. Speeds seem fine on small (<10000) data sets but quickly take more and more time as the counts go up.
In SQL Server 2008 R2 I have a table with four columns in it: Id, ParentId, ControlNum, ParentControlNum.
The Id and ParentId information is filled in. An Id always has a value, the ParentId is null if the row has no parent, otherwise its the the value of an Id within the table that represents the parent row.
The issue is that the Id and ParentIds are all over the place. All of the Ids are added to the table then they are processed to add the children. This is a set part of the problem and is not something that can be changed.
What I need to be able to do is to generate the ControlNum values in order obeying the Parent Child relationship. My current logic uses a bit of C# and SQL SELECT/UPDATE commands to accomplish this, but as mentioned performance is a great concern.
In Pseudo-Code
Select all Id's where the parent Id is null (All root entries)
Foreach (Id)
GenerateControlNum(Id, CurrentCounterValue, CurrentCounterValue)
GenerateControlNum(Id, CurrentCounterValue, ParentCounterValue)
Set Id's ControlNum to CurrentCounterValue
Set Id's ParentControlNum to CurrentCounterValue
Increment CurrentCounterValue
Select All Id's where ParentId == Id (All my direct children)
Foreach (ChildId)
GenerateControlNum(ChildId, CurrentCounterValue, Id's ControlNum);
Baseline is trying to make this execute faster, idealy completely in SQL would be preffered. I am trying along the lines of a CTE populated with the RootIds and then going through them with a MERGE statement but I can just not seem to get the counter value to work properly for setting the ControlNum values.
Is this even possible in SQL or is this too much of a procedural type of processing?
Example Table Data from how it currently runs: BEFORE
ID ParentId ControlNum ParentControlNum
8C821027-A6F9-E011-AB48-B499BAE13A62 756F981E-A6F9-E011-AB48-B499BAE13A62 0 NULL
D7DB6033-A6F9-E011-AB48-B499BAE13A62 756F981E-A6F9-E011-AB48-B499BAE13A62 0 NULL
D2E36033-A6F9-E011-AB48-B499BAE13A62 C9E36033-A6F9-E011-AB48-B499BAE13A62 0 NULL
8FE66033-A6F9-E011-AB48-B499BAE13A62 58E66033-A6F9-E011-AB48-B499BAE13A62 0 NULL
37EC6033-A6F9-E011-AB48-B499BAE13A62 2FEC6033-A6F9-E011-AB48-B499BAE13A62 0 NULL
41EC6033-A6F9-E011-AB48-B499BAE13A62 2FEC6033-A6F9-E011-AB48-B499BAE13A62 0 NULL
DDED6033-A6F9-E011-AB48-B499BAE13A62 BCED6033-A6F9-E011-AB48-B499BAE13A62 0 NULL
DC69981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
166A981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
4D6A981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
856A981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
F56A981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
2E6B981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
666B981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
9D6B981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
AFTER
ID ParentId ControlNum ParentControlNum
8C821027-A6F9-E011-AB48-B499BAE13A62 756F981E-A6F9-E011-AB48-B499BAE13A62 22 21
D7DB6033-A6F9-E011-AB48-B499BAE13A62 756F981E-A6F9-E011-AB48-B499BAE13A62 24 21
D2E36033-A6F9-E011-AB48-B499BAE13A62 C9E36033-A6F9-E011-AB48-B499BAE13A62 58 57
8FE66033-A6F9-E011-AB48-B499BAE13A62 58E66033-A6F9-E011-AB48-B499BAE13A62 69 68
37EC6033-A6F9-E011-AB48-B499BAE13A62 2FEC6033-A6F9-E011-AB48-B499BAE13A62 86 85
41EC6033-A6F9-E011-AB48-B499BAE13A62 2FEC6033-A6F9-E011-AB48-B499BAE13A62 88 85
DDED6033-A6F9-E011-AB48-B499BAE13A62 BCED6033-A6F9-E011-AB48-B499BAE13A62 95 94
DC69981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 0
166A981E-A6F9-E011-AB48-B499BAE13A62 NULL 1 1
4D6A981E-A6F9-E011-AB48-B499BAE13A62 NULL 2 2
856A981E-A6F9-E011-AB48-B499BAE13A62 NULL 3 3
F56A981E-A6F9-E011-AB48-B499BAE13A62 NULL 4 4
2E6B981E-A6F9-E011-AB48-B499BAE13A62 NULL 5 5
666B981E-A6F9-E011-AB48-B499BAE13A62 NULL 6 6
9D6B981E-A6F9-E011-AB48-B499BAE13A62 NULL 7 7
The data set I have is 104 entries right now so this is just the first 15. The objects with out parents are at the bottom, those are examples of root entries and have their control number and parent control number set to the same value. At the top of the table we see a few objects that have the same parents and so have matching parent control numbers and fairly close control numbers themselves (there must be row between ControlNum 22 and 24 also from parent 21 for example. same for the 86 to 88 jump, they are just not in the table next to each other).
Hope this makes it more clear.
EDIT: More clarity based on the answer given by Mikael
Below are ControlNum values displayed in the hierarchy based on their Id and ParentId information. Normally these would be listed 1, 2, 3 ... 8 but its easier not to clutter up the display with (child of) messages all over.
1
4
7
8
5
2
6
3
What I need is
1
2
3
4
5
6
7
8
This is why recursion has been the way that I have been going is I need to assign a ControlNum to the root object, and then the next object needs to be its first child followed by that objects children and so on before going on to the next root object.
I guess what I am saying is this is a breadth first and what I am in need of is a depth first.