带有XML的SQL Server 2005中的层次结构

时间:2011-04-23 01:48:49

标签: xml database sql-server-2005 hierarchy

我想知道无论如何在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

3 个答案:

答案 0 :(得分:8)

您可以使用递归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>

答案 1 :(得分: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]列。

这可能是你的另类选择吗?它表现得更好??

答案 2 :(得分:1)

我意识到这个答案有点晚了,但它可能有助于其他一些不幸的人正在寻找这个问题的答案。我使用hierarchyid和XML有类似的性能问题:

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

这是一个展示问题的片段。

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