Reputation: 1787
I am using SQL Server 2019 and I have a table like the following:
DROP TABLE IF EXISTS #Temp
SELECT *
INTO #Temp
FROM (
SELECT 1 Id, 'Name' ParameterName, 'John Smith' ParameterValue UNION
SELECT 1 Id, 'Age' ParameterName, '20' ParameterValue UNION
SELECT 1 Id, 'Gender' ParameterName, 'Male' ParameterValue UNION
SELECT 2 Id, 'Name' ParameterName, 'Jane Smythe' ParameterValue UNION
SELECT 2 Id, 'Age' ParameterName, '26' ParameterValue UNION
SELECT 2 Id, 'Org Group' ParameterName, 'Marketing' ParameterValue UNION
SELECT 2 Id, 'Gender' ParameterName, 'Female' ParameterValue) t
ORDER BY 1, 2
And I am wanting a query to transform this table into two rows with the Id, and an xml column with the value of the ParameterName as the xml tag and the value of the ParameterValue as the xml value e.g.:
<Age>20</Age>
<Gender>Male</Gender>
<Name>John Smith</Name>
I have tried the following but its not quite right:
SELECT t.Id
, (SELECT t1.ParameterName
, t1.ParameterValue
FROM #Temp t1
WHERE t1.Id = t.Id
FOR XML AUTO, TYPE)
FROM #Temp t
GROUP BY t.Id
SELECT t.Id
, (SELECT t1.ParameterName
, t1.ParameterValue
FROM #Temp t1
WHERE t1.Id = t.Id
FOR XML RAW, ELEMENTS, TYPE)
FROM #Temp t
GROUP BY t.Id
SELECT t.Id
, (SELECT t1.ParameterName
, t1.ParameterValue
FROM #Temp t1
WHERE t1.Id = t.Id
FOR XML PATH (''), TYPE)
FROM #Temp t
GROUP BY t.Id
Upvotes: 2
Views: 105
Reputation: 72119
If you know all the possible ParameterName
values up-front, you can just do conditional aggregation.
SELECT
t.Id,
MAX(CASE WHEN ParameterName = 'Name' THEN ParameterValue END) Name,
MAX(CASE WHEN ParameterName = 'Age' THEN ParameterValue END) Age,
MAX(CASE WHEN ParameterName = 'Gender' THEN ParameterValue END) Gender,
MAX(CASE WHEN ParameterName = 'Org Group' THEN ParameterValue END) Org_Group
FROM #Temp t
GROUP BY
t.Id
FOR XML PATH('Node'), ROOT('Root')
Without knowing the node names up-front, it becomes much harder, because neither FOR XML
nor .query
construction allow dynamic node names.
You need to construct it yourself, and you need to make sure to escape all necessary values.
In the below code, ParameterValue
is escaped, but ParameterName
only has spaces removed. You may need to check for other characters also.
SELECT
CAST(
CONCAT(
'<Node>',
STRING_AGG(
CONCAT(
'<',
REPLACE(ParameterName, ' ', '_'),
'>',
x.txt,
'</',
REPLACE(ParameterName, ' ', '_'),
'>'
),
''
),
'</Node>'
) AS xml
)
FROM #Temp t
CROSS APPLY (
SELECT ParameterValue [text()]
FOR XML PATH('')
) x(txt)
GROUP BY
t.Id
FOR XML PATH(''), ROOT('Root');
Upvotes: 1