SQL FOR XML use values as column names - sql-server

The FOR XML command uses column names to create the XML nodes. I need my nodes to be named after values I'm getting from the database. As far as I know you can't do something such as
SELECT Key AS Section
SECTION | KEY | VALUE
-----------------------------------------------------------
PageAddProduct | ErrorDateFormat | Incorrect value
PageAddProduct | ErrorNotSelected | Please select value
WidgetLogin | Title | Connexion
WidgetLogin | MailLabel | Mail
This is the desired XML output
<Resources>
<WidgetLogin>
<Title>Connexion</Title>
<MailLabel>Mail</MailLabel>
</WidgetLogin>
</Resources>
Not sure if you can get this with For Xml. Help would be much appreciated.

You can build your XML as a string and then cast to XML.
This sample code will work in SQL Server 2012 since it is using the concat function but it can easily be rewritten to use + instead.
select cast(concat('<Resources>',
(
select concat('<',T1.SECTION,'>',
(
select concat('<',T2.[KEY],'>',
(select T2.VALUE for xml path('')),
'</',T2.[KEY],'>')
from T as T2
where T1.SECTION = T2.SECTION
for xml path(''), type
).value('text()[1]', 'nvarchar(max)'),
'</',T1.SECTION,'>')
from T as T1
group by T1.SECTION
for xml path(''), type
).value('text()[1]', 'nvarchar(max)'),
'</Resources>') as xml)
SQL Fiddle

You can use FOR XML like below:
SELECT Section as Title, Value as MailLabel
FROM table
FOR XML PATH('WidgetLogin'), ROOT('Resources'), TYPE

Related

Extract attribute value from XML

I have data stored using XML tags in a column of a table. I am trying to pull data in a query from that column. This is a pared down skeletal version of the format of the XML and the query for a single node. The column type is XML.
<data>
<Company>
<GROUP_ID ControlType="xxxxxxxxx" ParentName="ppppppppp" Value="100" />
</Company>
</data>
This just will not pull the value "100" out no matter how I have tried. All I get is a blank, but not a NULL.
Is it because the data is not in a proper format or is my query just wrong? The p_table has the XML column (U_Xml).
select
pt.id,
x.y.value('(GROUP_ID)[1]', 'varchar(max)') AS [Group ID]
From p_table pt
CROSS APPLY pt.U_Xml.nodes('/data/Company') as x(y)
Thanks for any direction I can receive.
GROUP_ID element has no value, i.e. child text node.
It has just attributes.
Please try the following.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (id INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO #tbl (xmldata) VALUES
(N'<data>
<Company>
<GROUP_ID ControlType="xxxxxxxxx" ParentName="ppppppppp" Value="100"/>
</Company>
</data>');
-- DDL and sample data population, end
SELECT id
, c.value('#ControlType', 'VARCHAR(30)') AS ControlType
, c.value('#ParentName', 'VARCHAR(30)') AS ParentName
, c.value('#Value', 'INT') AS [Value]
FROM #tbl CROSS APPLY xmldata.nodes('/data/Company/GROUP_ID') AS t(c);
Output
+----+-------------+------------+-------+
| id | ControlType | ParentName | Value |
+----+-------------+------------+-------+
| 1 | xxxxxxxxx | ppppppppp | 100 |
+----+-------------+------------+-------+

SQL Server parse XML column to get a column value if other column value equals certain value

In SQL Server 2014 a table with a CustomColumns column that contains XML data with the following structure:
<CustomColumnsCollection>
<CustomColumn>
<Name>Brand</Name>
<DataType>0</DataType>
<Value>Duprim</Value>
</CustomColumn>
<CustomColumn>
<Name>LabelGroup</Name>
<DataType>0</DataType>
<Value />
</CustomColumn>
...
</CustomColumnsCollection>
I want to get value of column Value where column Name equals, i.e. 'Brand' (the following code is a part of bigger query, which I saved as VIEW):
MAX(DISTINCT PR.CustomColumns.value('(/CustomColumnsCollection/CustomColumn/Name="Brand"/Value)[0]', 'varchar(max)')) AS Brand
In this case I would like it to return 'Duprim'. How is this achieved?
Here is another method by using XPath predicate.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, CustomColumns XML);
INSERT INTO #tbl (CustomColumns)
VALUES
(N'<CustomColumnsCollection>
<CustomColumn>
<Name>Brand</Name>
<DataType>0</DataType>
<Value>Duprim</Value>
</CustomColumn>
<CustomColumn>
<Name>LabelGroup</Name>
<DataType>0</DataType>
<Value/>
</CustomColumn>
</CustomColumnsCollection>');
-- DDL and sample data population, end
DECLARE #param VARCHAR(30) = 'Brand';
SELECT ID
, c.value('(Value/text())[1]', 'VARCHAR(50)') AS [Value]
FROM #tbl
CROSS APPLY CustomColumns.nodes('/CustomColumnsCollection/CustomColumn[(Name/text())[1] eq sql:variable("#param")]') AS t(c);
-- hard-coded value
SELECT ID
, c.value('(Value/text())[1]', 'VARCHAR(50)') AS [Value]
FROM #tbl
CROSS APPLY CustomColumns.nodes('/CustomColumnsCollection/CustomColumn[(Name/text())[1] eq "Brand"]') AS t(c);
Output
+----+--------+
| ID | Value |
+----+--------+
| 1 | Duprim |
+----+--------+
To help you with the view that is consumed by the MS Excel.
It would be great if you could provide a minimal reproducible example:
(1) DDL and sample data population, i.e. CREATE table(s) plus INSERT, T-SQL statements.
(2) What you need to do, i.e. logic.
(3) Desired output based on the sample data in #1 above.
SQL for Excel
SELECT ID
, CustomColumns.value('(/CustomColumnsCollection/CustomColumn[(Name/text())[1] eq "Brand"]/Value/text())[1]', 'VARCHAR(50)') AS [Value]
FROM #tbl;
Try something like this:
SELECT
xc.value('(Value)[1]', 'varchar(50)')
FROM
PR
CROSS APPLY
PR.CustomColumns.nodes('/CustomColumnsCollection/CustomColumn') AS XT(XC)
WHERE
xc.value('(Name)[1]', 'varchar(50)') = 'Brand'
The .nodes() returns a list of XML fragments, each representing a <CustomColumn> node. Select the one with the Name value of Brand in the WHERE clause, and get the value of Value for that XML node

SQL Server XML parse issue

I need to parse XML into a SQL Server 2012 database. However, I cannot find any good guide to parse this kind XML (here is SELECT TOP 2 FROM table):
<ns2:SoftWare xmlns:ns2="http://www.example.com" xmlns:ns3="http://www.example2.com"><keyc>123-ABC</keyc><statusc>Y</statusc></ns2:SoftWare>
<ns2:custom-data xmlns:ns2="http://www.example.com/2"><timec>2016.01.02</timec><customer>8R</customer><keyc>8R</keyc><statusc>N</statusc></ns2:custom-data>
Any help, how I can parse "keyc" value from XML?
So, I can use it select clause / or insert it to database.
You can use the nodes and value to get that entity:
DECLARE #Data TABLE (XmlText XML)
INSERT #Data VALUES
('<ns2:SoftWare xmlns:ns2="http://www.example.com" xmlns:ns3="http://www.example2.com"><keyc>123-ABC</keyc><statusc>Y</statusc></ns2:SoftWare>'),
('<ns2:custom-data xmlns:ns2="http://www.example.com/2"><timec>2016.01.02</timec><customer>8R</customer><keyc>8R</keyc><statusc>N</statusc></ns2:custom-data>')
SELECT
Nodes.KeyC.value('.', 'VARCHAR(50)') AS KeyC
FROM #Data D
CROSS APPLY XmlText.nodes('//keyc') AS Nodes(KeyC)
This outputs the following:
KeyC
-----------
123-ABC
8R

Shredding XML with unknown schema

I have to shred XML with unknown schema to a table. I don't know what elements there are in XML. And I am also not aware of XML format. In some cases XML data is Attribute centric and in some cases it is element centric.
For Example -
I have two XML -
<Root>
<Recorset>
<RecordsetId>1</RecordsetId>
<RecordsetName>name1</RecordsetName>
</Recorset>
</Root>
AND
<Root>
<Recorset RecordsetId="2" RecordsetName="name2"></Recorset>
</Root>
XML can have any other element/attributes. I need to capture the elements/attributes name and respective data using EDGE table produced from OPENXML.
What is the simplest way of doing this?
I need output in given format -
RecodrsetId RecordsetName
1 Name1
2 Name2
something like this?
select
C.Name,
C.Value
from #Data.nodes('//*') as T(C)
outer apply (
select
T.C.value('local-name(.)', 'nvarchar(max)') as Name,
T.C.value('(./text())[1]', 'nvarchar(max)') as Value
union all
select
A.C.value('local-name(.)', 'nvarchar(max)') as Name,
A.C.value('.', 'nvarchar(max)') as Value
from T.C.nodes('#*') as A(C)
) as C
where C.Value is not null
sql fiddle demo

SQL Server table to xml

this time i have question how to convert MSSQL table to XML
My source SQL table:
+-----------+-----------------+
|atributname|atributvalue |
+-----------+-----------------+
|phone |222 |
|param4 |bbbbcdsfceecc |
|param3 |bbbbcdsfceecc |
|param2 |bbbbcdsfccc |
+-----------+-----------------+
Expected result sample:
<items>
<phone>222</phone>
<prama4>bbbbcdsfceecc</param4>
<param3>bbbbcdsfceecc</param3>
<param2>bbbbcdsfccc</param2>
</items>
I tried lot of variations of the following query
SELECT atributname,atributvalue
FROM sampletable FOR XML PATH (''), ROOT ('items');
but results are not good :( should be exactly like in "Expected result sample"
any help
ps
Script to create sampletable:
create table sampletable
(atributname varchar(20),
atributvalue varchar(20))
insert into sampletable (atributname,atributvalue)
values ('phone','222');
insert into sampletable (atributname,atributvalue)
values ('param4','bbbbcdsfceecc');
insert into sampletable (atributname,atributvalue)
values ('param3','bbbbcdsfceecc');
insert into sampletable (atributname,atributvalue)
values ('param2','bbbbcdsfccc');
That's not how FOR XML works. It's columns that get turned into XML elements, not rows. In order to obtain the expected result, you would need to have columns named phone, param4, and so on - not rows with these values in attributename.
If there are specific elements you want in the XML, you could perform a pivot on the data first, then use FOR XML.
Example of a pivot would be:
SELECT [phone], [param2], [param3], [param4]
FROM
(
SELECT attributename, attributevalue
FROM attributes
) a
PIVOT
(
MAX(attributevalue)
FOR attributename IN ([phone], [param2], [param3], [param4])
) AS pvt
FOR XML ROOT('items')
Of course the aggregate will only work if attributevalue is a numeric data type. If it's a character-type column, then you'll have some trouble with the pivot, as there are no built-in string aggregates in SQL server AFAIK...
ok
finally i have done this in several ways,
but this is simplest version suitable for medium dataset
declare #item nvarchar(max)
set #item= (SELECT '<' + atributname +'>' +
cast(atributvalue as nvarchar(max)) +'</' + atributname +'>'
FROM sampletable FOR XML PATH (''), ROOT ('items'));
select replace(replace(#item,'<','<'),'>','>')

Resources