简体   繁体   中英

SQL Query to XML with tag attributes

There is a table:

CREATE TABLE temp
    (ID int, name varchar(50));

INSERT INTO temp
    ([ID], [name])
VALUES
    (1, 'Value 1'),
    (2, 'Value 2');

Need SQL query returning the following result:

<root>
 <row>
  <param name="first">1</param>
  <param name="second">Value 1</param>
 </row>
 <row>
  <param name="first">2</param>
  <param name="second">Value 2</param>
 </row>
</root>

Estimated Query is:

SELECT
  [ID] as [param/@name['first']],
  [name] as [param/@name['second']]
FROM
  temp
for xml path('row'), root('root')

Please correct Query to make it work.

XQuery FLWOR expression gives you a full control on the shape of the XML. Check it out:

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (id INT PRIMARY KEY, [name] varchar(50));

INSERT INTO @tbl (id, [name])
VALUES (1, 'Value 1')
    , (2, 'Value 2');
-- DDL and sample data population, end

;WITH rs(xml_data) AS
(
    SELECT * 
    FROM @tbl
    FOR XML PATH('row'), TYPE, ROOT('root')
)
SELECT xml_data.query('<root>
{ 
    for $r in /root/row
    return 
    <row>
        <param name="first">{data($r/id/text())}</param>
        <param name="second">{data($r/name/text())}</param>
    </row>
}
</root>') AS xml_output
FROM rs;

Output

<root>
  <row>
    <param name="first">1</param>
    <param name="second">Value 1</param>
  </row>
  <row>
    <param name="first">2</param>
    <param name="second">Value 2</param>
  </row>
</root>

The simplest approach might be this:

SELECT  'first' as [param/@name]
        ,ID as [param]
        ,''
        ,'second' as [param/@name]
        ,[name] as [param] 
FROM temp t
FOR XML PATH('row'), root('root');

The idea in short:

The engine works down the columns and finds

  • We have to open a <root>
  • We have to open a <row> for each row of the set
  • Okay, the first column is a new element <param> , we have to open it.
  • Now the value ("first") has to be written as an attribute @name .
  • The next value ( ID ) is also living in <param> , which is still open. Add it as a text() node.
  • Well the next column is - uhm - empty??? However... First we must close the open <param> ...
  • Okay, the next column looks better. There is an element <param> ... Okay, the last one is closed, we have to open a new one!

  • and so on...

This also works with fragments of paths:

SELECT  'first' as [param/onemore/@name]
        ,ID as [param/onemore]
        ,'' AS [param]
        ,'second' as [param/onemore/@name]
        ,[name] as [param/onemore] 
FROM temp t
FOR XML PATH('row'), root('root');

The result

<root>
  <row>
    <param>
      <onemore name="first">1</onemore>
      <onemore name="second">Value 1</onemore>
    </param>
  </row>
  <row>
    <param>
      <onemore name="first">2</onemore>
      <onemore name="second">Value 2</onemore>
    </param>
  </row>
</root>

In this case we re-open <onemore> , but we stay within the open <param> .

You can achieve this with sub-queries:

SELECT  'first' as [param/@name],
        ID as [param],
        (SELECT 'second' as [param/@name], 
                name as [param] 
        FROM temp t1 WHERE t1.ID = t.ID 
        FOR XML PATH(''), TYPE )  
FROM temp t
FOR XML PATH('row'), root('root')

Output:

<root>
  <row>
    <param name="first">1</param>
    <param name="second">Value 1</param>
  </row>
  <row>
    <param name="first">2</param>
    <param name="second">Value 2</param>
  </row>
</root>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM