Мне нужна помощь в разборе XML в T-SQL - PullRequest
3 голосов
/ 29 января 2012

Может ли кто-нибудь помочь мне разобрать следующий XML в T-SQL (SQL Server 2005)?

<Tx>
    <T>1</T>
    <C>1</C>
    <T>2</T>
    <C>1</C>
    <T>3</T>
    <C>1</C>
    <T>4</T>
    <C>1</C>
</Tx>

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

SELECT
        Tx.query('T').value('.', 'varchar(10)') AS [Column 1],
        Tx.query('C').value('.', 'varchar(10)') AS [Column 2]
    FROM @MyXml.nodes('Tx') x(Tx)

но это не сработало, так как я получаю следующий результат:

Column 1    Column 2
--------    --------
1234        1111

ожидая (чего я хочу достичь):

Column 1    Column 2
--------    --------
1           1
2           1
3           1
4           1

Строка, очевидно, является допустимым XML, но допустима ли она для T-SQL?

Буду также признателен, если кто-нибудь предоставит ссылку, объясняющую, как работает XML в T-SQL.

Заранее спасибо.

Ответы [ 3 ]

5 голосов
/ 29 января 2012

Вот способ связать значения по позиции в. Первое T сопоставляется с первым C и т. Д.

declare @XML xml = 
'<Tx>
    <T>1</T>
    <C>4</C>
    <T>2</T>
    <C>3</C>
    <T>3</T>
    <C>2</C>
    <T>4</T>
    <C>1</C>
</Tx>'

select @XML.value('(/Tx/T[position() = sql:column("N.number")])[1]', 'int') as Column1,
       @XML.value('(/Tx/C[position() = sql:column("N.number")])[1]', 'int') as Column2
from master..spt_values as N
where N.type = 'P' and
      N.number between 1 and @XML.value('max((count(/Tx/T), count(/Tx/C)))', 'int')

С другой структурой XML, такой как , предложено на marc_s запрос на намного проще.

declare @XML xml = 
'<Tx>
  <row>
    <T>1</T>
    <C>4</C>
  </row>
  <row>
    <T>2</T>
    <C>3</C>
  </row>
  <row>
    <T>3</T>
    <C>2</C>
  </row>
  <row>
    <T>4</T>
    <C>1</C>
  </row>
</Tx>'

select T.R.value('T[1]', 'int') as Column1,
       T.R.value('C[1]', 'int') as Column2
from @XML.nodes('/Tx/row') as T(R)
3 голосов
/ 29 января 2012

Используйте это:

select a.t, b.c
from
(
    select t.c.value('.[1]', 'int') [t]
        , ROW_NUMBER() OVER(ORDER BY t.c) [rn]
    from @MyXml.nodes('Tx/T') t(c)
)a
join
(
    select t.c.value('.[1]', 'int') [c]
        , ROW_NUMBER() OVER(ORDER BY t.c) [rn]
    from @MyXml.nodes('Tx/C') t(c)
)b on b.rn = a.rn

или другим способом:

select t.t [T]
    , @MyXml.value('(Tx/C[position() = sql:column("rn")])[1]', 'int') [C]
from
(
    select t.c.value('.[1]', 'int') [t]
        , ROW_NUMBER() OVER(ORDER BY t.c) [rn]
    from @MyXml.nodes('Tx/T') t(c)
)t
3 голосов
/ 29 января 2012

Чего вы пытаетесь достичь ??

В вашем текущем операторе select будут перечислены все элементы <T> ниже <Tx> - но только те - не узлы <C> тоже - и выПохоже, вы хотите получить значения из обоих видов подузлов - правильно ??

Это даст вам все элементы из узлов <T> - это то, что вы ищете?

SELECT
    Tx.x.value('.', 'varchar(10)') AS [Column 1]
FROM @MyXml.nodes('Tx/T') Tx(x)

Это даст вам все элементы внутри узла <Tx>, включая их «тип» (C или T) - это то, что вы ищете?

SELECT
    ColumType = Tx.x.value('local-name(.)', 'varchar(10)'),
    ColumnValue = Tx.x.value('.', 'varchar(10)')
FROM @MyXml.nodes('Tx/*') Tx(x)

Обновление: в качестве ресурсов для обучения использованию XQuery в SQL Server, я бы порекомендовал

Ваш XML не подходит для того, что вы пытаетесь сделать -нет ничего, что «объединяет» элементы T и C, которые, очевидно, принадлежат друг другу, поэтому XQuery действительно ничего не может сделать, чтобы проанализировать это так, как вы этого хотите.

Если у вас был XML-код, подобный следующему:

<Tx>
   <Pair>
      <T>....</T>
      <C>....</C>
   </Pair>
   <Pair>
      <T>....</T>
      <C>....</C>
   </Pair>
   ....
</Tx>

тогда вы можете получить список Tx/Pair узлов и получить элементы T и C из этого фрагмента XML.Но прямо сейчас - все, что вы можете сделать, это проанализировать все 8 подузлов <Tx> и отобразить их значения - это действительно все, что вы можете сделать

...