SQL HierarchyId 有时会产生错误的路径

SQL HierarchyId Sometimes Producing Wrong Path

我有一个产品列表,使用 HierarchyId 排序,但对于某些项目,层次结构中向上的完整路径产生了错误的结果。仅针对少数...我将在下面进行演示:

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()

使用该查询我获得了结果:

它 returns 过程中的大部分路径都很好,生成

'Exterior > Render > Colour > White'

然而其中四个产生最后两个交换项,如

'Exterior > Render > White > Colour'

我这辈子都弄不明白为什么条款会互换,为什么只在某些条款上互换。层次结构看起来是正确的,并且子项的级别都是正确的。我需要你的帮助...

下面是用于从产品层次结构生成路径的函数,但我不明白它怎么可能是问题所在。

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

没有 ORDER BY 子句,您无法确定行顺序。将列 Level 添加到 @NamesTable table。将 ORDER BY 子句添加到要连接字符串的 SELECT 中。这应该有所帮助。

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