Правильно, вам нужно решить множество проблем с вашим образцом!
Во-первых, я дам вам ответ, хотя учтите, что для правильной иерархической обработки это должна была быть рекурсивная функция,поэтому предоставленные вами тестовые данные должны были быть созданы в постоянных таблицах, а не во временных (более простых), а затем я укажу несколько полезных методов, которые я использовал в них для решения проблемы.
ALTER FUNCTION GetTasks (@ParentId varchar(255)= NULL)
RETURNS
XML
BEGIN
DECLARE @ReturnXML XML
SELECT @ReturnXML =
(
SELECT
(
SELECT
CONVERT(XML,
--Main task start tag
'<'+master_t.TaskType+' Name="'+master_t.TaskName+'">'+
CONVERT(VARCHAR(MAX),
(
SELECT
dbo.GetTasks(master_t.TaskId),
(
SELECT
CONVERT(XML,'<'+DetailName+'>'+DetailValue+'</'+DetailName+'>')
FROM
TASK_DETAILS t
WHERE
TaskId = master_t.TaskId
FOR XML PATH(''),Type
),
(
SELECT Name,Value,Type FROM TASK_PARAMETERS t
WHERE TaskId=master_t.TaskId
FOR XML PATH('Parameter'),Type
) 'Parameters'
FOR XML PATH(''),Type
)
)
+
--Main task end tag
'</'+master_t.TaskType+'>'
)
FROM
TASK master_t
WHERE
--Effectively ignore the parentId field if it is not passed.
ISNULL(ParentTaskId,'') = CASE WHEN @ParentId IS NULL THEN '' ELSE @ParentId END
FOR XML PATH(''),Type
) 'TaskList' FOR XML PATH(''),Type
)
RETURN @ReturnXML
END
GO
Вызовэта функция выглядит следующим образом:
SELECT dbo.GetTasks(NULL)
Правильно отметить следующие приемы:
a) Вы можете вручную создавать узлы xml, просто создавая их из строк - это полезно, еслиимена узлов находятся в таблице.Единственное, о чем вам следует знать, - чтобы поместить открытый и закрывающий тег вокруг блока, вам, вероятно, придется сначала преобразовать блок в строку, прикрепить теги, а затем преобразовать все это в xml (piecemeal).не будет работать, так как функция convert-to-xml будет ожидать, что вы предоставите правильно сформированный XML.
b) Иногда вам приходится вкладывать вещи в скобки, чтобы получить тег вокруг всех вложенных тегов ... Пример делает этоПрояснение:
SELECT
TaskName
FROM TASK t
FOR XML PATH('SomeRoot')
даст:
<SomeRoot>
<TaskName>Get Report Parameters</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Loop Report Creation</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Report In Loop</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Get Email Addresses</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Loop Mail Creation</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Send Email In Loop</TaskName>
</SomeRoot>
Чтобы отобразить «SomeRoot» вокруг него, вы можете сделать это:
SELECT
(
SELECT
TaskName
FROM TASK t
FOR XML PATH(''),Type
)
FOR XML PATH('SomeRoot')
Еслиимя узла является статическим (обратите внимание на XML PATH ('') , тип , который в основном гарантирует, что путь XML возвращает данные типа XML для дальнейшей обработки и не экранирует их)
Еслиимя узла НЕ статично, вы застряли с чем-то вроде этого, с необходимостью преобразования в и из строки, чтобы это работало.
SELECT
CONVERT(XML,
'<'+DynamicName+'>' +
CONVERT(VARCHAR(MAX),
(
SELECT
TaskName
FROM TASK t
FOR XML PATH(''),Type
)
) +
'</'+DynamicName+'>'
)
FROM
(SELECT 'Test' as DynamicName) a
в) Что касается вашего вопроса о том, чтобы разные дочерние теги отображались на одном уровне, это довольно тривиально, и вам просто нужно помнить, что обычная проблема нескольких слоев выбора перестает быть проблемойс xml в качестве xml select просто возвращает один объект xml.Затем вы можете использовать XML PATH, чтобы объединить эти результаты и в дереве.
например,
SELECT
(SELECT top 1 * FROM TASK FOR XML PATH(''),Type),
(SELECT top 1 * FROM TASK_DETAILS FOR XML PATH(''),Type)
Вернет одну строку с двумя столбцами, но если вы затем примените XML PATH ('')В целом, вы объединили их на одном уровне
SELECT
(SELECT top 1 * FROM TASK FOR XML PATH(''),Type),
(SELECT top 1 * FROM TASK_DETAILS FOR XML PATH(''),Type)
FOR XML PATH('Root')
d) Имена столбцов для вас преобразуются в узлы, если с помощью XML PATH.Атрибуты довольно просты, так как вы просто присваиваете столбцу псевдоним, соответствующий подходящему xsl-пути, например, «MyNodeName \ @MyAttributeName», очевидно, это исключает атрибуты, которые также имеют динамическое имя.Для этого в этом примере я просто снова собрал xml из строк.Это, кстати, то, почему динамические имена узлов являются такой плохой идеей - вы в основном позволяете своей подпрограмме создавать новые имена атрибутов и имен узлов через данные в таблице ... это означает, что вы не можете создать приличную схему для своей подпрограммы, так каквы не знаете заранее, какие данные могут быть в таблице ...
Двигаемся дальше:)
Итак, учитывая эти строительные блоки, проще всего работать с самой глубокойУровень, и построить его блок за блоком, а затем объединить, как описано выше.
Я сделал это для вашего запроса, и в конце концов понял, что, чтобы заставить его работать иерархически (т.е. n-вложенные уровни), я должен был написать какфункция, возвращающая XML, которая вызывается с передачей ему родительского узла (чтобы функция знала, к чему фильтровать результирующий набор).Это умрет ужасной смертью, если ваша иерархия будет плохо сформирована и круговая.
Хорошо, надеюсь, есть что-то там, с чем вы можете работать.Это чисто ориентированное на XML PATH () решение - существуют альтернативные методы XML, которые могут быть полезны в различных ситуациях.