简体   繁体   中英

XML with row and column levels to SQL Server table

I have a table called XMLData that stores an XML file in the Data column. The structure of the XML is as follows:

<?xml version="1.0" encoding="utf-16"?>  
<table>    
    <id>{c566d133-8512-44c3-b6bd-ea0a9fe473d4}</id>    
        <rows>      
            <row>        
                <columns>          
                    <column name="Item" value="ITEM01" type="System.String" />          
                    <column name="Description" value="Description of item 01" type="System.String" />          
                    <column name="Key" value="1" type="System.Int32" />        
                </columns>      
            </row>      
            <row>        
                <columns>          
                    <column name="Item" value="ITEM02" type="System.String" />          
                    <column name="Description" value="Description of item 02" type="System.String" />          
                    <column name="Key" value="2" type="System.Int32" />        
                </columns>      
            </row>    
        </rows>    
    <key>Key</key>    
    <total>0</total>    
    <AddOnKey>0</AddOnKey>    
    <data />    
    <parameters />  
</table>

What I want is to query the XML and get a result like:

Item      | Description              | Key
------------------------------------------
ITEM01    | Description of item 01   | 1
ITEM02    | Description of item 02   | 2

What I've tried is:

SELECT 
    Tbl.Col.value('@name', 'nvarchar(128)'),
    Tbl.Col.value('@value', 'nvarchar(255)')
FROM
    (SELECT CAST(Data AS XML) AS d 
     FROM XMLData) AS d
CROSS APPLY 
    d.nodes('//row/columns/column') Tbl(Col)

But that doesn't return the desired result, because it return everything in two columns (name, value). I've thought about going in this direction:

SELECT 
    Tbl.Col.query('./columns')
FROM
    (SELECT CAST(Data As XML) AS d FROM XMLData) AS d
CROSS APPLY 
    d.nodes('//row') Tbl(Col)

This returns two rows with XML columns:

(No column name)
<columns><column name="Item" value="ITEM01" type="System.String" /><column name="Description" value="Description of item 01" type="System.String" /><column name="Key" value="1" type="System.Int32" /></columns>
<columns><column name="Item" value="ITEM02" type="System.String" /><column name="Description" value="Description of item 02" type="System.String" /><column name="Key" value="2" type="System.Int32" /></columns>

But than I don't know how I can get the separate columns.

You can try to use some calculation for row number, then use condition aggregate function by the row number.

SELECT
  MAX(CASE WHEN name = 'Item' then value end) 'Item', 
  MAX(CASE WHEN name = 'Description' then value end) 'Description', 
  MAX(CASE WHEN name = 'Key' then value end) 'Key'
FROM (
SELECT 
       Tbl.Col.value('@name', 'nvarchar(128)') name,
       Tbl.Col.value('@value', 'nvarchar(255)') value,
       ((ROW_NUMBER() OVER(ORDER BY Col)-1) / 3)rn 
FROM   (SELECT CAST(Data As XML) AS d FROM XMLData) AS d
CROSS APPLY d.nodes('//row/columns/column') Tbl(Col)
) t1
GROUP BY rn

sqlfiddle

Result

Item    Description             Key
ITEM01  Description of item 01  1
ITEM02  Description of item 02  2

You can try the below one. Replace @xml.nodes to tablename.columnname.nodes

SELECT DISTINCT
   i.y.value('@value', 'varchar(max)') AS Item,
  d.y.value('@value', 'varchar(max)') as "Description",
  k.y.value('@value', 'varchar(max)') as "Key"
FROM  @xml.nodes('//columns//column[@name = "Item"]') AS i(y)
    cross apply @xml.nodes('//columns//column[@name = "Description"]') AS d(y)
    cross apply @xml.nodes('//columns//column[@name = "Key"]') AS k(y)

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