SQL Server 2014从树结构中提取顶级CategoryID

时间:2016-06-06 04:27:44

标签: sql-server tree

我有一个包含大约10.000个节点的Tree结构 翻译成20多种语言 完全约230.000记录

表中的相关字段为:
LanguageID, CategoryID, ParentCategoryID, CategoryLevel, isLeaf, Expired, TopLevelCategoryID

我需要使用正确的值填充TopLevelCategoryID,因此CategoryID where CategoryParentID IS NULL --(or where CategoryLevel=1) 对于所有记录 isLeaf=0 and Expired=0 and TopLevelCategoryID is NOT NULL

经过google搜索后我写了这个查询

Declare @LanguageID nvarchar(10)='FR'

  ;WITH Explode AS
  (
    SELECT  categoryID AS major, 
            categoryID AS minor, 
            LanguageIDID, 
            CAST(CategoryID as nvarchar(max)) AS levels
    FROM dbo.Categories
    Where LanguageID=@LanguageID 
    AND CategoryLevel=1

    UNION ALL

    SELECT MJ.major, MN.categoryID, MN.LanguageID, MJ.levels +','+CAST(MN.CategoryID as nvarchar(max)) levels
    FROM Explode AS MJ
    JOIN dbo.Categories AS MN ON MJ.minor = MN.ParentCategoryID 
    WHERE MN.LanguageID=@LanguageID 
    AND (','+MJ.levels+',' NOT LIKE  '%'+CAST(MN.CategoryID as nvarchar(max))+',%')
    AND MN.Expired=0
  )

  Update c set TopLevelCategoryID= e.major
  FROM Explode e
  JOIN dbo.Categories c ON c.categoryID=e.minor
  WHERE c.LanguageID=@LanguageID
  AND c.TopLevelCategoryID IS NULL
  OPTION (MAXRECURSION 0)

有效,但即使添加了@LanguageID参数

,也非常慢

当然效率不高..

我也想知道它是不是更好的递归例程 对于categorylevel = 6到1 您在TopLevelCategoryID中为每个级别放置ParentCategoryID的值 但是我无法管理递归: - (

这里有一些带有1种语言的示例数据(抱歉但不能使用此数据创建sqlfiddle)

CREATE TABLE dbo.Categories (
    languageID nvarchar(3)  NULL,
    CategoryID int   NULL,
    ParentCategoryID int  NULL,
    CategoryLevel int  NULL,
    isLeaf bit NULL,
    Expired bit NULL,
    TopLevelCategoryID int NULL
)

INSERT INTO
Categories 
    (
        LanguageID, 
        CategoryID, 
        ParentCategoryID, 
        CategoryLevel, 
        isLeaf, 
        Expired, 
        TopLevelCategoryID
    )
VALUES 
    ('EN',10,NULL,1,0,0,NULL),
    ('EN',20,NULL,1,0,0,NULL),
    ('EN',30,NULL,1,0,0,NULL),
    ('EN',40,NULL,1,0,0,NULL),
    ('EN',107,20,2,0,0,NULL),
    ('EN',112,10,2,0,0,NULL),
    ('EN',145,20,2,0,0,NULL),
    ('EN',167,20,2,0,0,NULL),
    ('EN',182,30,2,0,0,NULL),
    ('EN',194,20,2,0,0,NULL),
    ('EN',199,145,3,0,0,NULL),
    ('EN',214,112,3,0,0,NULL),
    ('EN',345,182,3,1,0,NULL),
    ('EN',567,167,3,0,0,NULL),
    ('EN',682,194,3,0,0,NULL),
    ('EN',794,145,3,0,0,NULL),
    ('EN',814,199,4,0,0,NULL),
    ('EN',823,214,4,0,0,NULL),
    ('EN',846,214,4,1,0,NULL),
    ('EN',880,199,4,0,0,NULL),
    ('EN',896,567,4,1,0,NULL),
    ('EN',898,682,4,0,0,NULL),
    ('EN',1104,823,5,1,0,NULL),
    ('EN',1120,880,5,1,0,NULL),
    ('EN',1450,814,5,0,0,NULL),
    ('EN',1670,814,5,1,0,NULL),
    ('EN',1820,1450,6,0,0,NULL),
    ('EN',1940,1450,6,0,0,NULL)

有人可以提供一些提示吗?

谢谢!

  

突发新闻

我尝试了一种不同的方法,更适合我的技能,因此,将TopLevelCategoryID设置为parentCategoryID并使用此查询将此值从低CategoryLevel级别移至最高级别:

DECLARE @cnt int=1

WHILE @cnt < 8
BEGIN
    UPDATE c SET TopLevelCategoryID = COALESCE(c2.TopLevelCategoryID,c2.ParentCategoryID)
    FROM Categories cat
    JOIN Categories c2 
         ON c.ParentCategoryID=c2.CategoryID 
         AND c.LanguageID=c2.LanguageID
    WHERE c.CategoryLevel=@cnt
    AND c.Expired=0
    AND c2.Expired=0

    SET @cnt = @cnt + 1
END
来自初步测试的

似乎有效,但是处理时间从超过4小时传递到不到1秒,虽然它会很好我认为有一些错误:从我看到的,所有树结构都用CTE和递归处理:不能像现在看来那么简单:

有人可以帮忙找到我没有考虑过的错误吗? 谢谢!

1 个答案:

答案 0 :(得分:0)

肯定不是每个人的解决方案,但是对于我的具体要求效果很好,虽然既没有使用CTE也没有使用递归,只有重复:实际上需要事先知道重复的最大水平。但优点是,超过200,000条记录只需不到1秒,而开始时发布的CTE +递归解决方案超过250分钟(不是秒!)

DECLARE @cnt int=1

WHILE @cnt < 8
BEGIN
    UPDATE c SET TopLevelCategoryID = COALESCE(c2.TopLevelCategoryID,c2.ParentCategoryID)
    FROM Categories cat
    JOIN Categories c2 
         ON c.ParentCategoryID=c2.CategoryID 
         AND c.LanguageID=c2.LanguageID
    WHERE c.CategoryLevel=@cnt
    AND c.Expired=0
    AND c2.Expired=0

    SET @cnt = @cnt + 1
END