The code below I adapted from one of my production scripts. It will at least get you a working sequencer.Whether you store the sequence in the table or generate it on the fly is your call, best to take into consideration your particular scenario. if your sequences are of a known and limited depth and might end up looking like 1.5.9 storing them in the table might not be too bad (can cluster on that key), but if the sequences are potentially long or of n-tier depth calculating them on the fly isn't a bad option either; 1.5.9 doesn't look so bad, but 113202.156478.294732.746354 ... can get to be a bit much when it runs long.To give credit where credit's due; the solution below is inspired by techniques gleaned from some of Itzik Ben-Gan's articles in SqlMag; some sample data:DECLARE @Hierarchy TABLE(ID INT NOT NULL PRIMARY KEY, ParentID INT NULL);INSERT @HierarchySELECT 10481, 10413 UNION ALLSELECT 10482, 10413 UNION ALLSELECT 10483, 10413 UNION ALLSELECT 10484, 10413 UNION ALLSELECT 10485, 10413 UNION ALLSELECT 10486, 10413 UNION ALLSELECT 10487, 10413 UNION ALLSELECT 10492, 10413 UNION ALLSELECT 10493, 10413 UNION ALLSELECT 10499, NULL UNION ALLSELECT 10500, NULL UNION ALLSELECT 10501, NULL UNION ALLSELECT 10502, NULL UNION ALLSELECT 10503, NULL UNION ALLSELECT 10508, NULL UNION ALLSELECT 10515, NULL UNION ALLSELECT 10527, 10497 UNION ALLSELECT 10528, 10497 UNION ALLSELECT 10541, NULL UNION ALLSELECT 10714, 10498 UNION ALLSELECT 12676, 10497 UNION ALLSELECT 12680, 10497 UNION ALLSELECT 12681, 10418 UNION ALLSELECT 12682, NULL UNION ALLSELECT 10413, NULL UNION ALLSELECT 10418, NULL UNION ALLSELECT 10468, 10413 UNION ALLSELECT 10470, 10468 UNION ALLSELECT 10471, 10470 UNION ALLSELECT 10473, 10413 UNION ALLSELECT 10474, 10413 UNION ALLSELECT 10475, 10413 UNION ALLSELECT 10476, 10413 UNION ALLSELECT 10477, 10413 UNION ALLSELECT 10488, 10413 UNION ALLSELECT 10489, 10413 UNION ALLSELECT 10490, 10413 UNION ALLSELECT 10491, 10413 UNION ALLSELECT 10497, NULL UNION ALLSELECT 10498, NULL UNION ALLSELECT 10604, NULL
couple things for fun;DECLARE @MaxDepth TINYINT, @RootID INT;SET @MaxDepth=1;SET @RootID=10413;
the main course;DECLARE @MaxDepth TINYINT, @RootID INT;SET @MaxDepth=1;SET @RootID=NULL; --10413WITH HierarchyCTE ([ParentID],[ID],[ThreadDepth],[Sequence]) AS ( SELECT EM.[ParentID] , EM.[ID] , 0 AS [ThreadDepth] , CAST(EM.[ID] AS varbinary(max)) [Sequence] FROM @Hierarchy EM WHERE (@RootID IS NULL AND EM.[ParentID] IS NULL) OR (@RootID = EM.[ParentID]) UNION ALL SELECT HierarchyCTE.[ID] [ParentID] , EM.[ID] , HierarchyCTE.[ThreadDepth]+1 [ThreadDepth] ,CAST(HierarchyCTE.[Sequence] + CAST(EM.[ID] AS binary(4)) AS varbinary(max)) [Sequence] FROM HierarchyCTE INNER JOIN @Hierarchy EM ON HierarchyCTE.[ID]=EM.[ParentID] WHERE (@MaxDepth IS NULL OR HierarchyCTE.[ThreadDepth] < @MaxDepth)) SELECT [ParentID],[ID],[ThreadDepth],[Sequence] FROM HierarchyCTE ORDER BY [Sequence];
if you need to order the sequence by something other than the simple id you can add to the sequence;CAST(EM.[DateCol] AS binary(8))+CAST(EM.[ID] AS binary(4))
will order members by date then id, the sequences will become very long at depth, a further deturrent to saving the sequence in the table, but you're granted a lot of flexibilty in the exact row order you end up with - very useful if you need something other than or in addition to id order_____________________________wrote this on my TRS-80 COCO4<PakRat/>