I have a list of products, sorted using a HierarchyId, but for some of the items the full path up the hierarchy is producing the wrong result. Only for a few... Ill demonstrate below:
SELECT
ProductId
,Name
,FullName
,Hierarchy
,Hierarchy.ToString() as hierarchyString
,editor.ufn_Product_GetFullName(ProductId) as ufnGetFullName
,Hierarchy.GetLevel() as [level]
FROM Editor.Product
WHERE ProductId = 378
OR Hierarchy.ToString() like '/16/1/1/%'
OR Hierarchy.ToString() = '/16/1/'
OR Hierarchy.ToString() = '/16/'
OR Hierarchy.ToString() = '/'
ORDER BY Hierarchy.ToString()
Using that query i obtain the result:
Most of the paths it returns from the procedure are fine, producing
'Exterior > Render > Colour > White'
however four of them produce the last two terms swapped like
'Exterior > Render > White > Colour'
I can't for the life of me, figure out why the terms are swapped and why on only some. The hierarchy structure looks correct and the levels are all correct on the child items. I need your help...
Below is the function used to produce the path from the product hierarchy, though I don't understand how it could be the problem.
ALTER FUNCTION [Editor].[ufn_Product_GetFullName] ( @ID INT )
RETURNS VARCHAR(8000)
AS BEGIN
-- Create and insert names into temp table
DECLARE @NamesTable TABLE (Name varchar(8000));
INSERT @NamesTable (Name)
SELECT t1.Name
FROM ( SELECT ProductId, Hierarchy, Name
FROM Product WITH(NOLOCK)
WHERE (ProductId = @ID)) AS t2
CROSS JOIN Product AS t1
WHERE (t1.Hierarchy = t2.Hierarchy)
OR (t1.Hierarchy <> '/')
AND (t2.Hierarchy.IsDescendantOf(t1.Hierarchy) = 1)
ORDER BY t1.Hierarchy;
-- Define name string
DECLARE @Name VARCHAR(8000);
-- Coalesce names from temp table into one long string
SELECT @Name = COALESCE(@Name + ' > ', '') + Name
FROM @NamesTable
-- Return full string
RETURN @Name
END
Without ORDER BY
clause you cannot be sure of rows order. Add column Level
to @NamesTable
table. Add ORDER BY
clause to SELECT
where you are concating strings. This should help.
ALTER FUNCTION [Editor].[ufn_Product_GetFullName] ( @ID INT )
RETURNS VARCHAR(8000)
AS BEGIN
-- Create and insert names into temp table
DECLARE @NamesTable TABLE (Name varchar(8000), Level int);
INSERT @NamesTable (Name, Level)
SELECT t1.Name, t1.Hierarchy.getLevel()
FROM ( SELECT ProductId, Hierarchy, Name
FROM Product WITH(NOLOCK)
WHERE (ProductId = @ID)) AS t2
CROSS JOIN Product AS t1
WHERE (t1.Hierarchy = t2.Hierarchy)
OR (t1.Hierarchy <> '/')
AND (t2.Hierarchy.IsDescendantOf(t1.Hierarchy) = 1)
ORDER BY t1.Hierarchy;
-- Define name string
DECLARE @Name VARCHAR(8000);
-- Coalesce names from temp table into one long string
SELECT @Name = COALESCE(@Name + ' > ', '') + Name
FROM @NamesTable
ORDER BY Level
-- Return full string
RETURN @Name
END