http://sqlblog.com/blogs/john_paul_cook/archive/2009/10/03/displaying-hierarchical-data-indenting-the-output.aspx
John Paul Cook wrote a useful query for this that i actually used earlier this week
in short it uses a recursive CTE and uses string concatenation to set the ordering
;WITH BOMcte(ComponentID, Name, PerAssemblyQty, BOMLevel, ProductAssemblyID, Sort)
AS
(
SELECT b.ComponentID,
CAST(p.Name as nvarchar(100)),
b.PerAssemblyQty,
b.BOMLevel,
b.ProductAssemblyID,
CAST('\' + p.Name as nvarchar(254))
FROM Production.BillOfMaterials AS b
INNER JOIN Production.Product p
on b.ComponentID = p.ProductID
WHERE b.EndDate IS NULL -- only retrieve components still being used
and b.ComponentID = 775 -- specify a component to explode
UNION ALL
SELECT b.ComponentID,
CAST(REPLICATE ('| ' , b.BOMLevel) + p.Name as nvarchar(100)),
b.PerAssemblyQty,
b.BOMLevel,
b.ProductAssemblyID,
CAST(cte.Sort + '\' + p.Name as nvarchar(254))
FROM Production.BillOfMaterials as b
INNER JOIN Production.Product p
on b.ComponentID = p.ProductID
INNER JOIN BOMcte AS cte
ON b.ProductAssemblyID = cte.ComponentID
WHERE b.EndDate IS NULL -- only retrieve components still being used
)
SELECT Name, PerAssemblyQty
FROM BOMcte
ORDER BY Sort;
This is how i implemented it
WITH Counts
AS (
SELECT parent_ID ,
COUNT(id) AS cnt
FROM Contact_Heirarchy
WHERE Contact_Heirarchy.Discontinue_Date IS NULL
GROUP BY Parent_Id
),
Employee ( ID, [ParentId], Contact_ID, Name, ImmediateChildren )
AS (
SELECT Company_Heirarchy_ID ,
Contact_Heirarchy.Parent_ID ,
c.contact_ID ,
c.Reporting_Name AS name ,
ISNULL(cn.cnt, 0) AS ImmediateChildren
FROM Contact_Heirarchy
LEFT OUTER JOIN Contact c ON Contact_Heirarchy.contact_ID = c.Contact_ID
LEFT OUTER JOIN Counts cn ON Contact_Heirarchy.Company_Heirarchy_ID = cn.parent_id
WHERE Contact_Heirarchy.Discontinue_Date IS NULL
),
Tree
AS (
SELECT [Id] ,
[ParentId] ,
Contact_ID ,
0 AS [TreeLevel] ,
CAST('\' + ( cast( 999 - ImmediateChildren as varchar(3)) ) + Name AS VARCHAR(1000)) AS Sort ,
CAST(REPLICATE('| ', 0) + Name AS NVARCHAR(100)) Hierarchy ,
ParentNode.ImmediateChildren
FROM Employee AS ParentNode
WHERE ( Contact_ID in(@contactID))
UNION ALL
SELECT ChildNode.[Id] ,
ChildNode.[ParentId] ,
ChildNode.Contact_ID ,
LIT.[TreeLevel] + 1 AS [TreeLevel] ,
CAST(LIT.sort + '\' + (cast( 999 - ChildNode.ImmediateChildren as varchar(3)) ) + Name AS VARCHAR(1000)) AS Sort ,
CAST(REPLICATE('| ', LIT.TreeLevel + 1) + Name AS NVARCHAR(100)),
ChildNode.ImmediateChildren
FROM Employee AS ChildNode
INNER JOIN [Tree] LIT ON ( ChildNode.[ParentId] = LIT.[Id] )
WHERE ( ChildNode.[ParentId] IS NOT NULL )
)
SELECT Tree.* ,
c.Reporting_Name AS Contact
FROM Tree
INNER JOIN Contact c ON Tree.Contact_ID = c.Contact_ID
ORDER BY Tree.Sort