Как выполнить итерацию XML-поля в SQL Server с помощью функции value()

#sql-server #xml #tsql #xquery

#sql-сервер #xml #tsql #xquery

Вопрос:

У меня есть следующее поле XML ():

 <A>
  <B name="B1">
    <C>
      <D name="D1">
        <E name="E1"/>
        <E name="E2"/>
        <E name="E3"/>
      </D>
      <D name="D2">
        <E name="E4"/>
        <E name="E5"/>
        <E name="E6"/>
      </D>
    </C>
  </B>
  <B name="B3">
    <C>
      <D name="D11">
        <E name="E11"/>
        <E name="E22"/>
        <E name="E33"/>
      </D>
      <D name="D22">
        <E name="E44"/>
        <E name="E55"/>
        <E name="E66"/>
      </D>
    </C>
  </B>
</A>
 

Если я хочу использовать nodes() и value() получать данные из XML, что мне делать, результат должен быть таким:

B D E
B1 D1 E1
B1 D1 E2
B1 D1 E3
B2 D2 E4
..
B3 D22 E66

Я попробовал следующий запрос:

 SELECT NodePath.value('@name', 'varchar(100)') B,
    NodePath.value('(./C/D/@name)[1]', 'varchar(64)') D,
    NodePath.value('(./C/D/E/@name)[1]', 'varchar(100)') E
FROM XmlTable xt
cross apply xt.XmlField.nodes('/A/B') Node(NodePath)
 

но мне кажется, что для этого требуется только одно E из разных B

Комментарии:

1. Пример XML недопустим. В закрывающих тегах должен использоваться / символ, а не символ «». например: <D>...</D> .

2. @AlwaysLearning, sry, я это исправил.

Ответ №1:

 SELECT NodePath.value('@name', 'varchar(100)') B,
    --NodePath.value('(./C/D/@name)[1]', 'varchar(64)') D,
    --NodePath.value('(./C/D/E/@name)[1]', 'varchar(100)') E,
    d.d.value('@name', 'varchar(64)') AS D,
    e.e.value('@name', 'varchar(100)') AS E
FROM XmlTable xt
CROSS APPLY xt.XmlField.nodes('/A/B') AS Node(NodePath)
CROSS APPLY Node.NodePath.nodes('C/D') AS d(d)
CROSS APPLY d.d.nodes('E') AS e(e)
 

Комментарии:

1. Спасибо, это работает! И мне также интересно его производительность. Будет ли его производительность лучше, чем у следующего запроса? SELECT NodePath.value(../../../'@name', 'varchar(100)') B, NodePath.value('@../name', 'varchar(64)') AS D, NodePath.value('@name', 'varchar(100)') AS E FROM XmlTable xt CROSS APPLY xt.XmlField.nodes('/A/B/C/D/E') AS Node(NodePath)

2. ..@zening.chen . В общем, перемещение вверх по структуре / иерархии xml (от дочернего узла к родительскому узлу) с использованием parent:: или аббревиатуры ‘../’ является более дорогостоящим / дорогостоящим, чем сначала получение родительского, а затем дочерних элементов. Вы можете сравнить и проверить различия в двух планах выполнения (для подъема по иерархии требуется 2 дополнительных фильтра xpath). Это не означает, что ваше предложение будет медленнее. Более дорогостоящий запрос получает больше памяти, и иногда это может привести к тому, что дорогостоящий запрос будет выполняться быстрее, чем более дешевый. Просто протестируйте его в своей среде и выберите тот, который вам подходит.