【问题标题】:Hierarchy in SQL server 2005 with XML带有 XML 的 SQL Server 2005 中的层次结构
【发布时间】:2011-08-11 07:42:12
【问题描述】:

我想知道是否有在 SQL Server 2005 中选择层次结构并返回 xml 格式? 我有一个包含大量数据的数据库(大约 2000 到 3000 条记录),我现在使用 SQL Server 2005 中的一个函数来检索层次结构中的数据并返回一个 XML,但它似乎并不完美,因为它太慢了大量数据

这是我的功能

数据库

ID      Name      Parent       Order

功能

 CREATE FUNCTION [dbo].[GetXMLTree]
(
    @PARENT bigint
)
RETURNS XML
AS
    BEGIN
    RETURN /* value */
(SELECT [ID] AS "@ID",
        [Name] AS "@Name",
        [Parent] AS "@Parent",
        [Order] AS "@Order",
        dbo.GetXMLTree(Parent).query('/xml/item')
    FROM MyDatabaseTable
    WHERE [Parent]=@PARENT
    ORDER BY [Order]
    FOR XML PATH('item'),ROOT('xml'),TYPE)
    END

我想在层次结构中使用 XML,因为我有很多事情要做:) 任何最好的解决方案plzzzzz

【问题讨论】:

    标签: xml database sql-server-2005 hierarchy


    【解决方案1】:

    您可以使用递归 CTE 来构建层次结构并遍历层级来构建 XML。

    -- Sample data
    create table MyDatabaseTable(ID int,  Name varchar(10), Parent int, [Order] int)
    insert into MyDatabaseTable values
    (1, 'N1',     null, 1),
    (2, 'N1_1',   1   , 1),
    (3, 'N1_1_1', 2   , 1),
    (4, 'N1_1_2', 2   , 2),
    (5, 'N1_2',   1   , 2),
    (6, 'N2',     null, 1),
    (7, 'N2_1',   6   , 1)
    
    -- set @Root to whatever node should be root
    declare @Root int = 1
    
    -- Worktable that holds temp xml data and level
    declare @Tree table(ID int, Parent int, [Order] int, [Level] int, XMLCol xml)
    
    -- Recursive cte that builds @tree
    ;with Tree as 
    (
      select 
        M.ID,
        M.Parent,
        M.[Order],
        1 as [Level]
      from MyDatabaseTable as M
      where M.ID = @Root
      union all
      select 
        M.ID,
        M.Parent,
        M.[Order],
        Tree.[Level]+1 as [Level]
      from MyDatabaseTable as M
        inner join Tree
          on Tree.ID = M.Parent  
    )
    insert into @Tree(ID, Parent, [Order], [Level])
    select *
    from Tree
    
    
    declare @Level int
    select @Level = max([Level]) from @Tree
    
    -- Loop for each level
    while @Level > 0
    begin
    
      update Tree set
        XMLCol = (select
                    M.ID as '@ID',
                    M.Name as '@Name',
                    M.Parent as '@Parent',
                    M.[Order] as '@Order',
                    (select XMLCol as '*'
                     from @Tree as Tree2
                     where Tree2.Parent = M.ID
                     order by Tree2.[Order]
                     for xml path(''), type)
                  from MyDatabaseTable as M
                  where M.ID = Tree.ID
                  order by M.[Order]
                  for xml path('item'))
      from @Tree as Tree             
      where Tree.[Level] = @Level
    
      set @Level = @Level - 1
    end
    
    select XMLCol
    from @Tree
    where ID = @Root
    

    结果

    <item ID="1" Name="N1" Order="1">
      <item ID="2" Name="N1_1" Parent="1" Order="1">
        <item ID="3" Name="N1_1_1" Parent="2" Order="1" />
        <item ID="4" Name="N1_1_2" Parent="2" Order="2" />
      </item>
      <item ID="5" Name="N1_2" Parent="1" Order="2" />
    </item>
    

    【讨论】:

    • 使用 CTE 时不需要循环
    • @GeorgePolevoy - 如果不知道如何使用 CTE 构建分层 XML。如果您能提供一个答案,表明我很乐意给您 +1,请从中学习并删除我的答案。在你这样做之前,我会假设你不明白这个问题实际上是关于什么的。
    • @HieuNguyenTrung,我通过创建一个仅包含我在层次结构中需要的记录的临时表,然后在几个字段(id 和 parentId )。最初我的脚本需要几分钟才能运行,然后使用临时表和索引将其缩短到 4 秒。
    【解决方案2】:

    我意识到这个答案有点晚了,但它可能会对正在寻找这个问题的答案的其他不幸的人有所帮助。我在使用带有 XML 的 hierarchyid 时遇到过类似的性能问题:

    对我来说,最简单的解决方案实际上只是在选择为 XML 列之前在 hierarchyid 值上调用 ToString()。在某些情况下,这将我的查询速度提高了十倍!

    这是一个显示问题的 sn-p。

    create table #X (id hierarchyid primary key, n int)
    
    -- Generate 1000 random items
    declare @n int = 1000
    while @n > 0 begin
    
        declare @parentID hierarchyID = null, @leftID hierarchyID = null, @rightID hierarchyID = null
        select @parentID = id from #X order by newid()
        if @parentID is not null select @leftID = id from #X where id.GetAncestor(1) = @parentID order by newid()
        if @leftID is not null select @rightID = min(id) from #X where id.GetAncestor(1) = @parentID and id > @leftID
    
        if @parentID is null set @parentID = '/'
    
        declare @id hierarchyid = @parentID.GetDescendant(@leftID, @rightID)
        insert #X (id, n) values (@id, @n)
    
        set @n -= 1 
    end
    
    -- select as XML using ToString() manually
    select id.ToString() id, n from #X for xml path ('item'), root ('items')
    
    -- select as XML without ToString() - about 10 times slower with SQL Server 2012
    select id, n from #X for xml path ('item'), root ('items')
    
    drop table #X
    

    【讨论】:

      【解决方案3】:

      您期望使用 XML 有什么好处?当您无论如何都需要 XML 时,我没有完美的解决方案 - 但也许您也可以研究替代方案??

      使用递归 CTE(通用表表达式),您可以轻松地在单个结果集中获得整个层次结构,并且性能应该明显优于使用递归 XML 构建函数。

      查看此 CTE:

      ;WITH Hierarchy AS
      (
          SELECT
              ID, [Name], Parent, [Order], 1 AS 'Level'
          FROM
              dbo.YourDatabaseTable
          WHERE
              Parent IS NULL
      
          UNION ALL
      
          SELECT
              t.ID, t.[Name], t.Parent, t.[Order], Level + 1 AS 'Level'
          FROM
              dbo.YourDatabaseTable t
          INNER JOIN  
              Hierarchy h ON t.Parent = h.ID
      )
      SELECT *
      FROM Hierarchy
      ORDER BY [Level], [Order]
      

      这为您提供了一个结果集,其中所有行都返回,按级别排序(根级别为 1,每个向下级别增加 1)及其[Order] 列。

      这对您来说可以替代吗?效果更好吗??

      【讨论】:

      • 还有要订购的吗?我不能像你那样订购它,这是不正确的:(
      • @chrno love:在你的外部 SELECT 声明上指定一个 ORDER BY,这样它对你来说是“正确的”......
      • 我想像 XML 的后代一样订购它
      猜你喜欢
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      • 1970-01-01
      • 2011-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多