2012-01-29 3 views
3

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

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

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

+0

Define «не работает» ... – JNK

+0

я обновил вопрос – TheBlueSky

+0

Видимо, вы хотите, чтобы соответствовать 'C' к' Т *. Не имеет значения, какие значения парятся друг с другом или это нормально, чтобы выбрать любую ценность? –

ответ

5

Вот способ сопоставления значений по положению. Первый 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 как suggested по 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) 
+0

Получение следующих ошибок при попытке запуска первого (второе дает похожие ошибки, но разные строки #) Msg 139, Level 15, State 1, Line 0 Невозможно присвоить значение по умолчанию локальной переменной. Msg 137, Level 15, State 2, Line 13 Должен объявить скалярную переменную "@XML". – deutschZuid

+0

@JamesJiao - это синтаксис, который работает в SQL Server 2008. Если вы используете SQL Server 2005, вам нужно разделить объявление переменной '@ XML' и присваивание на два утверждения типа' declare @XML xml; set @XML = 'xml идет здесь'; ' –

+0

Я выбрал это как ответ на свой вопрос, хотя мне не нравится, насколько уродливым может быть код для простого прочтения ... но если это так, то это как это. Мой совет состоит в том, чтобы сформировать XML, как то, что Микаэль Эрикссон и Маркос предложили ... когда это возможно. – TheBlueSky

3

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

Ваш текущий оператор выбора будет перечислить все элементы <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) 

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

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

Если вы имели XML что-то вроде этого:

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

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

+0

Извините, это была ошибка копирования-вставки. Я обновил вопрос. – TheBlueSky

+0

@TheBlueSky: вы не можете разобрать его так, как хотите - нет никакой «структуры», которая хранит соответствующие элементы '' и' ', поэтому в XPath нет ничего, что можно было бы проанализировать для этих элементов как« column1 »и« column1 », column2 ", как вы хотите. –

+0

Да, если у меня есть XML, подобный вашему примеру, я бы стал простой задачей, но, увы, это не тот случай. Во всяком случае, спасибо за ссылки. – TheBlueSky

3

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

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 
+0

Это только обходной путь; вы имеете в виду, что T-SQL не может разобрать XML-документ? – TheBlueSky

+1

@ TheBlueSky, Как я знаю - нет. –

+1

Вызывает * бит * подозрительный для заказа экземпляром 'nodes', но, видимо, он использует идентификатор из XML Reader' '. Адам Мачаник рассказал об этом в [Uniquely Identification XML Nodes с DENSE_RANK] (http://sqlblog.com/blogs/adam_machanic/archive/2009/08/03/uniquely-identifying-xml-nodes-with-dense-rank. ASPX). +1 –

Смежные вопросы