Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
803 views
in Technique[技术] by (71.8m points)

sql server - Create XML with variable element names from a data table with values and names

I wasn't able to find a relevant post, so I decided to ask.

I have the following table in my SQL Server database:

ID       attname    value 
---------------------------------
22405543 blktradind N 
22405543 brkref     IRVTGB2X
22405543 buyamt     104650.2000 
22405543 buycurref  USD 
22405543 Buy53ref 
22405543 Buy56ref 
22405543 Buy57ref   IRVTBEBB

How can I convert this table by using FOR XML variations to a dynamic XML result based on the "attname" that each message has?

For the excerpt above, the desired result would be:

<Message id=22405543>
  <blktradind>N</blktradind>
  <brkref>IRVTGB2X</brkref>
  <buyamt>104650.2000</buyamt>
  <buycurref>USD</buycurref>
  <buy53ref />
  <buy56ref />
  <buy57ref>IRVTBEBB</buy57ref>
</Message>

Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is not possible normally. SQL Server does not support variable column aliases for your output. But there are workarounds:

string concatenation

The approach is a bit ugly, as I normally would not prefer to create XML via string concatenation. But by wrapping the value with a SELECT FOR XML PATH itself, this is even stable with forbidden characters like <> or &.

DECLARE @tbl TABLE(ID BIGINT,attname NVARCHAR(100),value NVARCHAR(100));
INSERT INTO @tbl VALUES 
 (22405543,'blktradind','N') 
,(22405543,'brkref','IRVTGB2X') 
,(22405543,'buyamt','104650.2000')  
,(22405543,'buycurref','USD')  
,(22405543,'Buy53ref',NULL) 
,(22405543,'Buy56ref',NULL) 
,(22405543,'Buy57ref','IRVTBEBB');

WITH DistinctIDs AS
(
    SELECT DISTINCT ID FROM @tbl
)
SELECT ID AS [@id]
      ,(
        SELECT CAST(N'<' + attname + N'>' + ISNULL((SELECT value AS [*] FOR XML PATH('')),N'') + N'</' + attname + N'>' AS XML)
        FROM @tbl AS tbl
        WHERE tbl.ID=DistinctIDs.ID
        FOR XML PATH(''),TYPE
       )
FROM DistinctIDs
FOR XML PATH('Message')

The result

<Message id="22405543">
  <blktradind>N</blktradind>
  <brkref>IRVTGB2X</brkref>
  <buyamt>104650.2000</buyamt>
  <buycurref>USD</buycurref>
  <Buy53ref />
  <Buy56ref />
  <Buy57ref>IRVTBEBB</Buy57ref>
</Message>

dynamic SQL

You could build the full statement dynamically and use EXEC(@cmd) to execute it. Something like this:

(Attention!!: The SELECT TOP 1 to get the ID is not appropriate for actual data!)

DECLARE  @cmd NVARCHAR(MAX)=
(
    SELECT 'SELECT ''' + CAST((SELECT TOP 1 ID FROM @tbl) AS NVARCHAR(100)) + ''' AS [@id] ' 
    + (
    SELECT ',''' + ISNULL(value,'') + ''' AS [' + attname + ']'
    FROM  @tbl
    FOR XML PATH('')
    )
    + ' FOR XML PATH(''Message'')'
);
EXEC(@cmd)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...