Selecting XML nodes with SQL Server - sql

My XMLData is stored under table.[column] : dbo.promotions.[PromotionDiscountData]
and the XML looks like the following when i expand it:
<ArrayOfPromotionDiscountBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PromotionDiscountBase xsi:type="OrderPromotionDiscount">
<DiscountType>Fixed</DiscountType>
<DiscountAmount>5.0000</DiscountAmount>
</PromotionDiscountBase>
</ArrayOfPromotionDiscountBase>
I would like to export a report and flatten out the xml as a column with everything else in the dbo.promotions table.
What would be the best way to get the DiscountType and DiscountAmount Out of the xml?
Thanks!

Please try the following.
SQL
-- DDL and data population, start
DECLARE #tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY,[xmlData] XML NOT NULL);
INSERT INTO #tbl([xmlData])
VALUES
(N'<ArrayOfPromotionDiscountBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PromotionDiscountBase xsi:type="OrderPromotionDiscount">
<DiscountType>Fixed</DiscountType>
<DiscountAmount>5.0000</DiscountAmount>
</PromotionDiscountBase>
</ArrayOfPromotionDiscountBase>');
-- DDL and data population, end
SELECT ID
, col.value('(DiscountType)[1]', 'VARCHAR(30)') AS [DiscountType]
, col.value('(DiscountAmount)[1]', 'DECIMAL(10,4)') AS [DiscountAmount]
FROM #tbl AS tbl
CROSS APPLY tbl.[xmlData].nodes('/ArrayOfPromotionDiscountBase/PromotionDiscountBase') AS tab(col);

Related

SQL Parse xml column data

I have very little experience with SQL Server. Here is what I am trying to accomplish:
I have a table with many rows. Every row contains a column named "Config". The data stored in the Config column is of the xml type. The xml structure looks like this:
<root>
<path1>
<path2>
<path3>true</path3>
</path2>
</path1>
</root>
I am trying to go through every row in the table and find the percentage of true to false values of <path3>.
I looked at some SQL documentation and tried to use the value() function I am having difficulties extracting the XML data from the column:
select Config.value('(/root/path1/path2/path3)[1]','nvarchar(max)') from [MyDB].[dbo].[MyTable]
Here is the result of my query:
I would like to query and extract data from the XML "Config" column of my table and aggregate that data into columns.
You need to specify namespaces in the query when xml is built with namespaces. For example
CREATE TABLE tbl (Config xml);
INSERT INTO tbl (Config)
VALUES ('<root xmlns="abc">
<path1>
<path2>
<path3>true</path3>
</path2>
</path1>
</root>') ;
Then
with xmlnamespaces (DEFAULT 'abc')
select Config.value('(/root/path1/path2/path3)[1]','nvarchar(max)') path3Txt
from tbl;
or explicit specification
with xmlnamespaces ('abc' as x)
select Config.value('(/x:root/x:path1/x:path2/x:path3)[1]','nvarchar(max)') path3Txt
from tbl;
You would need to use CROSS APPLY. Check it out.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, [Config] XML);
INSERT INTO #tbl
VALUES (N'<root>
<path1>
<path2>
<path3>true</path3>
</path2>
</path1>
</root>')
, (N'<root>
<path1>
<path2>
<path3>false</path3>
</path2>
</path1>
</root>');
-- DDL and sample data population, end
;WITH rs AS
(
SELECT ID
, col.value('(./text())[1]','VARCHAR(20)') AS Result
FROM #tbl tbl
CROSS APPLY tbl.[Config].nodes('/root/path1/path2/path3') AS tab(col)
)
SELECT * FROM rs;

SQL Update XML Value stored in ntext colum

I need to update two values within XML data that is stored in a ntext column. I have a copy of the database to test with, and I haven't been successful with the information I have found.
Here is a sample the XML that I need to update:
<?xml version="1.0" encoding="utf-16"?>
<cmnReportExportParameters xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DSNs>
<ReportDSN>
<Name>Name</Name>
<Database>DBName</Database>
<Server />
<User>user</User>
<Password>removed </Password>
<DevelopmentName>DBName</DevelopmentName>
</ReportDSN>
</DSNs>
</cmnReportExportParameters>
I need to update the "user" and "password" fields within this XML data. This is part of a legacy CMS application, and I am simply supporting the system (I'm not the developer).
I can cast the data successfully select Name, Parameters, CAST(parameters as xml) from tablename
Any guidance is appreciated.
This is far from ideal, but this is the only way I can think to do it. As your column is the wrong data type (ntext) you can't use the modify XQUERY command. Thus, you have to insert your data into a temporary table, update it, and then reinsert it. This is not going to be great for performance, but it works. As I said before, fixing the data type will make this far easier:
CREATE TABLE [sample] (YourIDCol int IDENTITY(1,1),
NotXML ntext);
INSERT INTO [sample] (NotXML)
VALUES (
N'<?xml version="1.0" encoding="utf-16"?>
<cmnReportExportParameters xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DSNs>
<ReportDSN>
<Name>Name</Name>
<Database>DBName</Database>
<Server />
<User>user</User>
<Password>removed </Password>
<DevelopmentName>DBName</DevelopmentName>
</ReportDSN>
</DSNs>
</cmnReportExportParameters>');
GO
CREATE TABLE #UpdateXML (ID int, ActualXML xml);
INSERT INTO #UpdateXML (ID,ActualXML)
SELECT YourIDCol,
TRY_CONVERT(xml,NotXML)
FROM [sample]
WHERE TRY_CONVERT(xml,NotXML) IS NOT NULL
AND YourIDCol = 1; --if you need it
UPDATE #UpdateXML
SET ActualXML.modify('replace value of (cmnReportExportParameters/DSNs/ReportDSN/User/text())[1] with ("NewUsername")');
UPDATE #UpdateXML
SET ActualXML.modify('replace value of (cmnReportExportParameters/DSNs/ReportDSN/Password/text())[1] with ("NewPassword")');
UPDATE S
SET NotXML = CONVERT(ntext,CONVERT(nvarchar(MAX),U.ActualXML)) --yuck
FROM [sample] S
JOIN #UpdateXML U ON S.YourIDCol = U.ID;
SELECT *
FROM [sample];
DROP TABLE #UpdateXML;
GO
DROP TABLE [sample];

Convert xml text in a cell to Columns

Our front end development team saves surveys in a SQL database table as xml text. Each survey has different set of fields and need help on how to automatically convert the cell holding the xml text to multiple columns.
Below is an example of the xml text in a cell which needs to be split into individual columns.
<?xml version="1.0" encoding="utf-16"?>
<root>
<userid>JS 30/08/1981</userid>
<column___1>0</column___1>
<column___2>1</column___2>
<column___3>0</column___3>
<column___4>0</column___4>
<column___5>0</column___5>
<column___6>0</column___6>
<column___7>0</column___7>
<column___8>0</column___8>
<column___9>0</column___9>
<column___1_0>0</column___1_0>
<column___1_1>0</column___1_1>
<column___1_2>0</column___1_2>
<column___1_3>0</column___1_3>
<column___1_4>0</column___1_4>
<column___1_5>0</column___1_5>
<column___1_6>0</column___1_6>
<column___1_7>0</column___1_7>
<column___1_8>0</column___1_8>
<column___1_9>0</column___1_9>
<column___2_0>0</column___2_0>
<column___2_1>0</column___2_1>
<column___D_S>0</column___D_S>
<column___A_S>2</column___A_S>
<column___S_S>0</column___S_S>
<userid___u_i_d>5</userid___u_i_d>
</root>
I created a test table using the syntax below:
CREATE TABLE [dbo].[XmlTest](
[id] [int] IDENTITY(1,1) NOT NULL,
[surveyxml] [xml] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
I then loaded 2 records into the test table(the 1st being the XML you have in your example).
Use a query like below:
SELECT
fields.value('(userid/text())[1]', 'varchar(50)') as userid,
fields.value('(column___1/text())[1]', 'varchar(50)') as column1,
fields.value('(column___2/text())[1]', 'varchar(50)') as column2,
fields.value('(column___3/text())[1]', 'varchar(50)') as column3
FROM
xmltest CROSS APPLY
surveyxml.nodes('/root') AS Root(fields)
The following results are returned:
You can add all the fields you want to the query, and change the data type if you know what it is. Good Luck
You can make this as generic dynamic code like this:
drop table if exists #tmp
DECLARE #XML as xml
SET #XML = N'<?xml version="1.0" encoding="utf-16"?>
<root>
<userid>JS 30/08/1981</userid>
<column___1>0</column___1>
<column___2>1</column___2>
<column___3>0</column___3>
<column___4>0</column___4>
<column___5>0</column___5>
<column___6>0</column___6>
<column___7>0</column___7>
<column___8>0</column___8>
<column___9>0</column___9>
<column___1_0>0</column___1_0>
<column___1_1>0</column___1_1>
<column___1_2>0</column___1_2>
<column___1_3>0</column___1_3>
<column___1_4>0</column___1_4>
<column___1_5>0</column___1_5>
<column___1_6>0</column___1_6>
<column___1_7>0</column___1_7>
<column___1_8>0</column___1_8>
<column___1_9>0</column___1_9>
<column___2_0>0</column___2_0>
<column___2_1>0</column___2_1>
<column___D_S>0</column___D_S>
<column___A_S>2</column___A_S>
<column___S_S>0</column___S_S>
<userid___u_i_d>5</userid___u_i_d>
</root>
'
/* First find all the column names and values */
SELECT
b.value('local-name(.)','VARCHAR(50)') AS ColumnName,
b.value('.','VARCHAR(MAX)') AS ColumnValue
into #tmp
FROM #xml.nodes('/root') x(x)
CROSS APPLY x.nodes('*') a(b)
/* Now build the select */
declare #sql nvarchar(max)=''
select #sql=#sql+'
'+iif(#sql='','',',')+''''+ ColumnValue + '''['+ColumnName+']'
from #tmp
set #sql='select '+#sql
exec sp_executesql #sql

Separate XML node values into separate rows in SQL

I have a SQL table with a XML column. The value of the column looks like this:
<StudentGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StudentIds>
<int>3000</int>
<int>3001</int>
<int>3002</int>
<int>8</int>
<int>9</int>
</StudentIds>
</StudentGroup>
I want to get the each StudentIDs in a separate row instead of it in one row. Here is what I have done:
select
xmlColumn.value('(/StudentGroup/StudentIds)[1]','varchar(max)') as IDs
from myTable
This select statement returns the IDs in one row. Like this:
30003001300289
What is want is
3000
3001
3002
8
9
Please help! Thanks in advance.
When you have the XML in a variable:
DECLARE #x XML = '
<StudentGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StudentIds>
<int>3000</int>
<int>3001</int>
<int>3002</int>
<int>8</int>
<int>9</int>
</StudentIds>
</StudentGroup>';
SELECT
n.v.value('.','INT') AS ID
FROM
#x.nodes('/StudentGroup/StudentIds/int') AS n(v);
When you have the XML in a table:
DECLARE #x XML = '
<StudentGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StudentIds>
<int>3000</int>
<int>3001</int>
<int>3002</int>
<int>8</int>
<int>9</int>
</StudentIds>
</StudentGroup>';
DECLARE #t TABLE(
x XML
);
INSERT INTO #t(x)VALUES(#x);
SELECT
n.v.value('.','INT') AS ID
FROM
#t
CROSS APPLY x.nodes('/StudentGroup/StudentIds/int') AS n(v);

Xquery to return rows with restricted nodes

I have a table where a column contains XML data. Now i want to retrieve those xml data with restriction of nodes. Kindly see the following example for more explanation on my scenario,
declare #table table (id int, xmlfield xml) insert into #table select 1,'<Root xmlns="">
<Sample>
<Issue>
<Level>one</Level>
<Descp>First Example</Descp>
</Issue>
<Issue>
<Level>two</Level>
<Descp>Second Example</Descp>
</Issue>
</Sample> </Root>'
select * from #table
Now i need the following result set
Id XMLfield
1 first example
ie, for the selected level,i need the decription for it. More clearly, the node should be restricted for <level>one</level>
(need: What is the description for level one ?)
thanks in advance
Have a look at the xml Data Type Methods
select id,
xmlfield.value('(//Issue[Level = "one"]/Descp/text())[1]', 'varchar(100)') as XMLField
from #table
The XQuery you're looking for is
//Issue[Level = "one"]/Descp/data()