Как преобразовать вложенную иерархию XML в таблицу SQL - PullRequest
3 голосов
/ 02 марта 2010

Использование MSSQL 2008 и XQUERY

Рассмотрим следующий XML, хранящийся в таблице:

<ROOT>
  <WrapperElement>
    <ParentElement ID=1>
      <Title>parent1</Title>
      <Description />
      <ChildElement ID="6">
        <Title>Child 4</Title>
        <Description />
        <StartDate>2010-01-25T00:00:00</StartDate>
        <EndDate>2010-01-25T00:00:00</EndDate>
      </ChildElement>
      <ChildElement ID="0">
        <Title>Child1</Title>
        <Description />
        <StartDate>2010-01-25T00:00:00</StartDate>
        <EndDate>2010-01-25T00:00:00</EndDate>
      </ChildElement>
      <ChildElement ID="8">
        <Title>Child6</Title>
        <Description />
        <StartDate>2010-01-25T00:00:00</StartDate>
        <EndDate>2010-01-25T00:00:00</EndDate>
      </ChildElement>
    </ParentElement>
  </WrapperElement>
</Root>

Я хочу разложить этот xml на что-то вроде

PE!ID | PE!Title | PE!Description | CE!ID | CE!Title | CE!StartDate |...
1     | parent1  |                | 6     | child 4  |  2010-... |
1     | parent1  |                | 0     | child1   | 2010-...  |

и т.д.

Примечание: в этом примере может быть много ChildElements на ParentElement. Я экспериментировал с xquery, однако я не смог перемещаться по сложным элементам как таковым.

По сути, я пытаюсь сделать прямо противоположное тому, что FOR XML делает с таблицей, только с гораздо более упрощенным набором данных для работы.

Есть идеи о том, куда идти дальше или как этого добиться?

Спасибо

1 Ответ

6 голосов
/ 02 марта 2010

Как насчет этого (я объявил @input переменной XML-типа данных с вашим содержимым XML - замените соответственно):

SELECT
    Parent.Elm.value('(@ID)[1]', 'int') AS 'ID',
    Parent.Elm.value('(Title)[1]', 'varchar(100)') AS 'Title',
    Parent.Elm.value('(Description)[1]', 'varchar(100)') AS 'Description',
    Child.Elm.value('(@ID)[1]', 'int') AS 'ChildID',
    Child.Elm.value('(Title)[1]', 'varchar(100)') AS 'ChildTitle',
    Child.Elm.value('(StartDate)[1]', 'DATETIME') AS 'StartDate',
    Child.Elm.value('(EndDate)[1]', 'DATETIME') AS 'EndDate'
FROM
    @input.nodes('/ROOT/WrapperElement/ParentElement') AS Parent(Elm)
CROSS APPLY
    Parent.Elm.nodes('ChildElement') AS Child(Elm)

Вы в основном перебираете все узлы /ROOT/WrapperElement/ParentElemet (как псевдотаблица Parent(Elm)), и для каждой из этих записей вы затем делаете CROSS APPLY для дочерних элементов, содержащихся внутри этого ParentElement, и извлекаете необходимая информация.

Должен работать - надеюсь!

...