2016-03-04 1 views
4

У меня есть таблица, которую я хотел бы преобразовать в формат XML. Таблица называется TempTable и содержит данные, как например:TSQL для форматирования XML

REF  DESC  QTY 
100001 Normal 1 
100002 OOH  1 

Мне нужно, чтобы создать XML в этом заданном формате:

<row> 
    <LIN NUM="1"> 
    <FLD NAME="REF">100001</FLD> 
    <FLD NAME="DES">Normal</FLD> 
    <FLD NAME="QTY">1</FLD> 
    </LIN> 
    <LIN NUM="2"> 
    <FLD NAME="REF">100002</FLD> 
    <FLD NAME="DES">OOH</FLD> 
    <FLD NAME="QTY">1</FLD> 
    </LIN> 
</row> 

Я попытался следующий код:

SET @line = (SELECT '1' AS '@NUM', REF AS 'REF', DES AS 'DES', QTY AS 'QTY' FROM tempTable WHERE ORDER= @ORDER 
FOR XML PATH('LIN')) 

SELECT @line 
FOR XML PATH 

Однако это дает:

<row> 
    <LIN NUM="1"> 
    <REF>100001</REF> 
    <DES>Normal</DES> 
    <QTY>1</QTY> 
    </LIN> 
    <LIN NUM="1"> 
    <REF>100002</REF> 
    <DES>OOH</DES> 
    <QTY>1</QTY> 
    </LIN> 
</row> 

Кто-нибудь знает, как я могу:

  • A) Изменить атрибут «Lin» «Num» быть инкрементным на основе количества записей для этого заказа?
  • B) Добавьте атрибут «Имя» в данные «LIN» и измените имена полей на «FLD». Когда я пытаюсь изменить название «FLD» он concats значения на одном узле, как таковой:

    <row> 
        <LIN NUM="1"> 
        <FLD>100001Normal1</FLD> 
        </LIN> 
        <LIN NUM="1"> 
        <FLD>100002OOH1</FLD> 
        </LIN> 
    </row> 
    

Я предполагаю, что, если я могу добавить атрибут «NAME», что бы выделить значения?

Любые советы/помощь были бы весьма полезны.

Благодаря

ответ

5
declare @tempTable table (Ref int, Des varchar(100), Qty int) 
insert into @tempTable values (100001, 'Normal', 1), (100002, 'OOH', 1) 

SELECT ROW_NUMBER() OVER (ORDER BY Ref) AS '@NUM', 
    'REF' AS 'FLD/@NAME', REF AS 'FLD', '', 
    'DES' AS 'FLD/@NAME', DES AS 'FLD', '', 
    'QTY' AS 'FLD/@NAME', QTY AS 'FLD' 

FROM @tempTable 
FOR XML PATH('LIN'), ROOT ('row') 

производит:

<row> 
    <LIN NUM="1"> 
    <FLD NAME="REF">100001</FLD> 
    <FLD NAME="DES">Normal</FLD> 
    <FLD NAME="QTY">1</FLD> 
    </LIN> 
    <LIN NUM="2"> 
    <FLD NAME="REF">100002</FLD> 
    <FLD NAME="DES">OOH</FLD> 
    <FLD NAME="QTY">1</FLD> 
    </LIN> 
</row> 

с небольшой помощью https://stackoverflow.com/a/25412657/4473405, потому что без пустых строк между узлом и атрибутом выбором, SQL Server выдает ошибку:

Attribute-centric column 'FLD/@NAME' must not come after a non-attribute-centric sibling in XML hierarchy in FOR XML PATH.

EDIT: как уже упоминалось в комментариях, this post объясняет, почему работает пустой трюк.

Резюмируя:

  • в FOR XML PATH, столбцы без имени становятся текстовыми узлами
    • NULL или '' поэтому становятся пустыми текстовыми узлами
    • вы можете преобразовать именованный столбец неназванного один за используя AS *
    • Это помогает отделить предыдущие выходные узлы от следующего, так что SQL Server знает, например, для запуска нового элемента для следующего столбца.В противном случае, он запутывается, когда, например, атрибут уже существует на том, что он думает, что это элемент «текущий»
+0

Большое спасибо за ваш быстрый и простое решение! – robbiecutting

+2

Я не знал трюка с пустой струной и был просто озадачен этим. Ницца ... – Shnugo

+1

@ Шнуго Что-то о том, что на самом деле делает трюк. http://stackoverflow.com/a/29234102/569436 –

0
DECLARE @t TABLE (ref varchar(10), descr varchar(10), qty varchar(3)) 
insert into @t 
values('100001', 'Normal', '1'),('10002','OOH','1') 

SELECT ROW_NUMBER() OVER (ORDER BY a.ref) AS '@NUM', 
(SELECT 'REF' AS 'FLD/@NAME' 
,ref AS 'FLD' 
FROM @t AS FLD 
WHERE FLD.ref = a.ref 
FOR XML PATH(''), TYPE), 
(SELECT 'DESCR' AS 'FLD/@DESCR' 
,descr AS 'FLD' 
FROM @t AS FLD 
WHERE FLD.ref = a.ref 
FOR XML PATH(''), TYPE), 
(SELECT 'QTY' AS 'FLD/@QTY' 
,QTY AS 'FLD' 
FROM @t AS FLD 
WHERE FLD.ref = a.ref 
FOR XML PATH(''), TYPE) 
FROM @t AS a 
FOR XML PATH('LIN'), ROOT('row') 
+0

Не могли бы вы объяснить это? –