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 |
+----+-------------+------------+-------+
Related
I'm trying to parse XML data in SQL Server. I have a XML column in a table, the XML stored in it can vary by type, but they all inherit from the same base type.
Row 1: has XML like so:
<Form>
<TaskType>1</TaskType>
--Other Properties ...
</Form>
Row 2: has XML like so:
<License>
<TaskType>2</TaskType>
--Other Properties ...
</License>
Normally I might parse XML with this T-SQL code snippet:
SELECT
xmlData.A.value('.', 'INT') AS Animal
FROM
#XMLToParse.nodes('License/TaskType') xmlData(A)
This doesn't work since in a view since I'm dependent on the name to find the node.
How can I always find the TaskType XML element in my XML content?
Please try the following solution.
XPath is using asterisk * as a wildcard.
http://www.tizag.com/xmlTutorial/xpathwildcard.php
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT #tbl (xmldata) VALUES
(N'<Form>
<TaskType>1</TaskType>
<TaskName>Clone</TaskName>
<!--Other XML elements-->
</Form>'),
(N'<License>
<TaskType>2</TaskType>
<TaskName>Copy</TaskName>
<!--Other XML elements-->
</License>');
-- DDL and sample data population, end
SELECT ID
, c.value('(TaskType/text())[1]', 'INT') AS TaskType
, c.value('(TaskName/text())[1]', 'VARCHAR(20)') AS TaskName
FROM #tbl
CROSS APPLY xmldata.nodes('/*') AS t(c);
Output
ID
TaskType
TaskName
1
1
Clone
2
2
Copy
Apparently you can just interate the nodes like so without being aware of their name:
SELECT xmlData.A.value('.', 'INT') AS Animal
FROM #XMLToParse.nodes('node()/TaskType') xmlData(A)
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
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
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,'<','<'),'>','>')
I am using a table with an XML data field to store the audit trails of all other tables in the database.
That means the same XML field has various XML information. For example my table has two records with XML data like this:
1st record:
<client>
<name>xyz</name>
<ssn>432-54-4231</ssn>
</client>
2nd record:
<emp>
<name>abc</name>
<sal>5000</sal>
</emp>
These are the two sample formats and just two records. The table actually has many more XML formats in the same field and many records in each format.
Now my problem is that upon query I need these XML formats to be converted into tabular result sets.
What are the options for me? It would be a regular task to query this table and generate reports from it. I want to create a stored procedure to which I can pass that I need to query "<emp>" or "<client>", then my stored procedure should return tabular data.
does this help?
INSERT INTO #t (data) SELECT '
<client>
<name>xyz</name>
<ssn>432-54-4231</ssn>
</client>'
INSERT INTO #t (data) SELECT '
<emp>
<name>abc</name>
<sal>5000</sal>
</emp>'
DECLARE #el VARCHAR(20)
SELECT #el = 'client'
SELECT
x.value('local-name(.)', 'VARCHAR(20)') AS ColumnName,
x.value('.','VARCHAR(20)') AS ColumnValue
FROM #t
CROSS APPLY data.nodes('/*[local-name(.)=sql:variable("#el")]') a (x)
/*
ColumnName ColumnValue
-------------------- --------------------
client xyz432-54-4231
*/
SELECT #el = 'emp'
SELECT
x.value('local-name(.)', 'VARCHAR(20)') AS ColumnName,
x.value('.','VARCHAR(20)') AS ColumnValue
FROM #t
CROSS APPLY data.nodes('/*[local-name(.)=sql:variable("#el")]') a (x)
/*
ColumnName ColumnValue
-------------------- --------------------
emp abc5000
*/
Neither xyz432-54-4231 nor abc5000 is valid XML.
You can try to select only one particular format with a like statement, f.e.:
select *
from YourTable
where YourColumn like '[a-z][a-z][a-z][0-9][0-9][0-9][0-9]'
This would match 3 letters followed by 4 numbers.
A better option is probably to add an extra column to the table, where you save the type of the logging. Then you can use that column to select all "emp" or "client" rows.
An option would be to create a series of views that present the aduit table, per type in the relations that you're execpting
for example
select
c.value('name','nvarchar(50)') as name,
c.value('ssn', 'nvarchar(20)') as ssn
from yourtable
cross apply yourxmlcolumn.nodes('/client') as t(c)
you could then follow the same pattern for the emp
you could also create a view (or computed column) to identify each xml type like this:
select yourxmlcolumn.value('local-name(/*[1])', 'varchar(100)') as objectType
from yourtable
Use open xml method
DECLARE #idoc int
EXEC sp_xml_preparedocument #idoc OUTPUT, #xmldoc
SELECT * into #test
FROM OPENXML (#idoc, 'xmlfilepath',2)
WITH (Name varchar(50),ssn varchar(20)
)
EXEC sp_xml_removedocument #idoc
after you get the data in the #test
and you can manipulate this.
you may be put the diff data in diff xml file.