【问题标题】:SQL Server 2014 Extract Top Level CategoryID from Tree StructureSQL Server 2014 从树结构中提取顶级 CategoryID
【发布时间】:2016-06-08 06:53:06
【问题描述】:

我有一个包含大约 10.000 个节点的树结构 翻译成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

的所有记录

在谷歌上搜索了很多之后,我写了这个查询

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 和递归处理的:不可能像我现在看起来那么简单:

有人可以帮我找出我没有考虑和做错的东西吗? 谢谢!

【问题讨论】:

  • 这看起来像是一次性工作,所以您可能不需要浪费时间优化它。因此,它不会很快:(','+MJ.levels+',' NOT LIKE '%'+CAST(MN.CategoryID as nvarchar(max))+',%') 实际上你在like 中失去了领先的“,”。
  • 我不太了解那个过滤器。 MJ.minor = MN.ParentCategoryID 是否有很多重复项,我的意思是每个类别可能会出现在不同的级别上?
  • 能否请您提供示例数据。您的查询对我来说有点模糊:) 递归部分似乎是类别表。不知何故,您还可以将其与 Explode 表连接起来。我确定这部分会降低性能。实际上,您正在将类别加入其上层的 parent_category。在类别表上运行递归查询后,您可以加入 Explode。然后也许你可以将它加入到探索表中。
  • 嗨!实际上,它不是一次性工作,而是每周工作,因为每周都会添加一些类别,而另一些类别会被删除。是的,我在复制时丢失了前导“,”。 MJ.minor=MN.CategoryParentID '应该' 将 CTE 的 categoryID 与类别表的 ParentCategoryID 加入
  • @Eralper 当然!刚刚添加

标签: sql-server tree


【解决方案1】:

当然这不是每个人的解决方案,但是对于我的具体要求来说效果很好,尽管既不使用 CTE 也不使用递归,只使用重复:实际上需要提前知道重复的最大级别。但优点是,与开头发布的 CTE+Recursion 解决方案超过 250 分钟(不是几秒!)相比,超过 200.000 条记录只需不到 1 秒的时间

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

【讨论】:

    猜你喜欢
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    相关资源
    最近更新 更多