Иерархия в SQL Server 2005 с XML - PullRequest
3 голосов
/ 23 апреля 2011

Интересно, есть ли в любом случае выбрать иерархию в 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 ]

8 голосов
/ 23 апреля 2011

Вы можете использовать рекурсивный 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>
3 голосов
/ 23 апреля 2011

Какую выгоду вы ожидаете от использования XML? У меня нет идеального решения для случая, когда вам нужен XML во что бы то ни стало - но, возможно, вы могли бы также изучить альтернативы ??

С помощью рекурсивного CTE (Common Table Expression) вы можете легко получить всю свою иерархию в одном наборе результатов, и производительность должна быть заметно выше, чем при выполнении рекурсивной функции построения 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].

Может ли это быть альтернативой для вас? Это работает лучше?

1 голос
/ 23 июля 2014

Я понимаю, что этот ответ немного запоздал, но он может помочь другому несчастливому человеку, который ищет ответы на эту проблему.У меня были похожие проблемы с производительностью при использовании hierarchyid с XML:

Для меня оказалось, что самым простым решением было просто вызвать ToString() для значений hierarchyid перед выбором в качестве столбца XML.В некоторых случаях это ускорило мои запросы в десять раз!

Вот фрагмент кода, в котором обнаружена проблема.

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
...