replace XML variable in sql [duplicate] - sql

This question already has answers here:
Updating SQL Server XML node
(2 answers)
Closed 4 years ago.
How do I replace the variable value of xml in sql? I need to change the values of ID and Text.
Sample XML
<Values>
<ValueList>
<Entry key="Num" type="Values">
<value ID="1" Text="One" />
</Entry>
<Entry key="Name" type="Values">
<value ID="2" Text="two" />
</Entry>
</ValueList>
</Values>

You can modified the ID value like following. Here I am updating ID="1" to "111", similarly you can change the text for a specific text using modify.
DECLARE #XML XML
SET #XML= '<Values> <ValueList> <Entry key="Num" type="Values"> <value ID="1" Text="One" /> </Entry> <Entry key="Name" type="Values"> <value ID="2" Text="two" /> </Entry> </ValueList> </Values>'
SET #XML.modify('replace value of (Values/ValueList/Entry/value[#ID eq ("1")]/#ID)[1] with ("1111")')
select #XML
If you want to use variables, it can be achieved like following.
DECLARE #XML XML
Declare #IDTOReplace VARCHAR(5)='1'
DECLARE #IDWithReplace VARCHAR(5) = '111'
SET #XML= '<Values> <ValueList> <Entry key="Num" type="Values"> <value ID="1" Text="One" /> </Entry> <Entry key="Name" type="Values"> <value ID="2" Text="two" /> </Entry> </ValueList> </Values>'
SET #XML.modify('replace value of (Values/ValueList/Entry/value[#ID eq sql:variable("#IDTOReplace")]/#ID)[1] with sql:variable("#IDWithReplace")')
select #XML
If you want to change the Text based on some Id, it can be achieved like following.
DECLARE #XML XML
Declare #IDTOReplace VARCHAR(5)='1'
DECLARE #TextToReplace VARCHAR(100) = 'NewText'
SET #XML= '<Values> <ValueList> <Entry key="Num" type="Values"> <value ID="1" Text="One" /> </Entry> <Entry key="Name" type="Values"> <value ID="2" Text="two" /> </Entry> </ValueList> </Values>'
SET #XML.modify('replace value of (Values/ValueList/Entry/value[#ID eq sql:variable("#IDTOReplace")]/#Text)[1] with sql:variable("#TextToReplace")')
select #XML

Related

Reading xml Structure in sql server 2012

Sample Xml Structure
<?xml version="1.0" encoding="UTF-8"?>
<XmlSerializableHashtable xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Entries>
<Entry>
<key xsi:type="xsd:string">col1</key>
<value xsi:type="xsd:string">500</value>
</Entry>
<Entry>
<key xsi:type="xsd:string">col2</key>
<value xsi:type="xsd:string">0/60,1/1000</value>
</Entry>
<Entry>
<key xsi:type="xsd:string">col3</key>
<value xsi:type="xsd:string">localhost</value>
</Entry>
</Entries>
</XmlSerializableHashtable>
No i am trying to get value where key is col3
I am trying with the Xquery
Declare #x xml;
Set #x = (Select valuefrom sometable)
Select #x.query('/Entries/Entry/')
This Query will be helpful.
DECLARE #xmlData AS XML
DECLARE #sRawData AS VARCHAR(2000)
SET #sRawData = '<?xml version="1.0" encoding="UTF-8"?>
<XmlSerializableHashtable xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Entries>
<Entry>
<key xsi:type="xsd:string">col1</key>
<value xsi:type="xsd:string">500</value>
</Entry>
<Entry>
<key xsi:type="xsd:string">col2</key>
<value xsi:type="xsd:string">0/60,1/1000</value>
</Entry>
<Entry>
<key xsi:type="xsd:string">col3</key>
<value xsi:type="xsd:string">localhost</value>
</Entry>
</Entries>
</XmlSerializableHashtable>'
SET #xmlData = CAST(#sRawData AS XML)
SELECT MainDataCenter.Col.value('(key)[1]','varchar(max)') AS [key]
,MainDataCenter.Col.value('(value)[1]','varchar(max)') AS Value
FROM #xmlData.nodes('/XmlSerializableHashtable/Entries/Entry') AS MainDataCenter(Col)
WHERE MainDataCenter.Col.value('(key)[1]','varchar(max)') = 'col3'

How to get value from XML in stored procedure?

Can you all help me for this problem?
I want to get value from following XML in sql stored procedure. I don't get vlaue if 'xsi:type="ActiveDirectoryItem"' is in tag 'anyType', and 'ActiveDirectoryItems' tag is also with URLs. How can i do to get only values?
<?xml version="1.0" encoding="utf-8" ?>
<ActiveDirectoryItems xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<Items>
<anyType xsi:type="ActiveDirectoryItem">
<FirstName />
<MiddleInitial />
<LastName />
<DisplayName>Migrate-group</DisplayName>
<UserPrincipalName />
<PostalAddress />
<ResidentialAddress />
<Title />
<HomePhone />
<OfficePhone />
<Mobile />
<Fax />
<Email>Migrate-group#gmail.com</Email>
<Url />
<AccountName>Migrate-group</AccountName>
<DistinguishedName />
<IsAccountActive>false</IsAccountActive>
<ManagedBy />
<Manager />
<CompareType>0</CompareType>
<Description />
<Department />
<Company />
<Type />
</anyType>
</Items>
<GlobalCatalog />
</ActiveDirectoryItems>
The format i want to get is as the following:
DisplayName Email Account Name
Migrate-group Migrate-group#gmail.com Migrate-group
you can use the value keyword
Example:
DECLARE #MyXml XML = '<Root><SomeData>100</SomeData></Root>'
DECLARE #Something INT
SELECT #Something = #MyXml.value('(//Root/SomeData)[1]', 'INT')

Extracting data from XML using OpenXML in SQL Server

I have a xml which I want it to be extracted using OpenXML within SQL Server
Here is the sample XML
<row>
<student_token>7</student_token>
<student_ssn>552</student_ssn>
<alternate_id>20</alternate_id>
<old_ssn xsi:nil="true" />
<alien_num xsi:nil="true" />
<last_name>A</last_name>
<first_name>B</first_name>
<middle_init xsi:nil="true" />
<drivers_license_num xsi:nil="true" />
<gpa_highschool xsi:nil="true" />
<created_dt>2006-07-13T11:15:08.320</created_dt>
<created_how>4</created_how>
<modified_dt>2008-02-14T00:00:00</modified_dt>
<modified_by>4</modified_by>
<primary_street2 xsi:nil="true" />
<primary_street3 xsi:nil="true" />
<primary_country xsi:nil="true" />
<email_address xsi:nil="true" />
<address_start_dt xsi:nil="true" />
<address_end_dt xsi:nil="true" />
<entrance_iv_dt xsi:nil="true" />
<entrance_iv_by xsi:nil="true" />
<exit_iv_dt>2006-11-02T00:00:00</exit_iv_dt>
<exit_iv_by>156</exit_iv_by>
<foreign_address_indicator>N</foreign_address_indicator>
<foreign_postal_code xsi:nil="true" />
<pin>J27841</pin>
<web_id>J08614 </web_id>
<prior_name xsi:nil="true" />
<orig_eps xsi:nil="true" />
<web_role>STU1</web_role>
<heal_limit_flag>N</heal_limit_flag>
<email_address_2>test#test.com</email_address_2>
<cellular_telephone>415</cellular_telephone>
<alt_loan_debt xsi:nil="true" />
<web_last_login xsi:nil="true" />
<foreign_country_code xsi:nil="true" />
<entrance_iv_dt_grad_plus xsi:nil="true" />
<entrance_iv_by_grad_plus xsi:nil="true" />
<failed_logins>0</failed_logins>
<hispanic xsi:nil="true" />
<race xsi:nil="true" />
<primary_phone_number_intl xsi:nil="true" />
<security_version>0</security_version>
<failed_challenge_response>0</failed_challenge_response>
<require_pin_reset xsi:nil="true" />
</row>
The query should extract into 3 fields for each row
FieldName
FieldValue
IsNull
For example the first row should be
FieldName = student_token - The node name would be the field name
FieldValue = 7
IsNull = false - IsNull is based on the attribute xsi:nil="true"
How can I do this?
Sample data with namespace added.
declare #xml xml
set #xml =
'<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<student_token>7</student_token>
<student_ssn>552</student_ssn>
<alternate_id>20</alternate_id>
<old_ssn xsi:nil="true" />
<alien_num xsi:nil="true" />
<last_name>A</last_name>
<first_name>B</first_name>
<middle_init xsi:nil="true" />
<drivers_license_num xsi:nil="true" />
<gpa_highschool xsi:nil="true" />
<created_dt>2006-07-13T11:15:08.320</created_dt>
<created_how>4</created_how>
<modified_dt>2008-02-14T00:00:00</modified_dt>
<modified_by>4</modified_by>
<primary_street2 xsi:nil="true" />
<primary_street3 xsi:nil="true" />
<primary_country xsi:nil="true" />
<email_address xsi:nil="true" />
<address_start_dt xsi:nil="true" />
<address_end_dt xsi:nil="true" />
<entrance_iv_dt xsi:nil="true" />
<entrance_iv_by xsi:nil="true" />
<exit_iv_dt>2006-11-02T00:00:00</exit_iv_dt>
<exit_iv_by>156</exit_iv_by>
<foreign_address_indicator>N</foreign_address_indicator>
<foreign_postal_code xsi:nil="true" />
<pin>J27841</pin>
<web_id>J08614 </web_id>
<prior_name xsi:nil="true" />
<orig_eps xsi:nil="true" />
<web_role>STU1</web_role>
<heal_limit_flag>N</heal_limit_flag>
<email_address_2>test#test.com</email_address_2>
<cellular_telephone>415</cellular_telephone>
<alt_loan_debt xsi:nil="true" />
<web_last_login xsi:nil="true" />
<foreign_country_code xsi:nil="true" />
<entrance_iv_dt_grad_plus xsi:nil="true" />
<entrance_iv_by_grad_plus xsi:nil="true" />
<failed_logins>0</failed_logins>
<hispanic xsi:nil="true" />
<race xsi:nil="true" />
<primary_phone_number_intl xsi:nil="true" />
<security_version>0</security_version>
<failed_challenge_response>0</failed_challenge_response>
<require_pin_reset xsi:nil="true" />
</row>'
Using openxml.
declare #idoc int
exec sp_xml_preparedocument #idoc out, #xml, '<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>'
select FieldName,
FieldValue,
isnull([IsNull], 0)
from openxml(#idoc, '/row/*',1)
with (
FieldName varchar(50) '#mp:localname',
FieldValue varchar(50) '.',
[IsNull] bit '#xsi:nil'
)
exec sp_xml_removedocument #idoc
Using the XML data type:
;with xmlnamespaces('http://www.w3.org/2001/XMLSchema-instance' as ns)
select T.N.value('local-name(.)', 'varchar(50)') as FieldName,
T.N.value('.', 'varchar(50)') as FieldValue,
isnull(T.N.value('#ns:nil', 'bit'), 0) as [IsNull]
from #xml.nodes('/row/*') as T(N)
Not sure if you have that XML as a SQL variable or inside a table - question is very unclear .....
If you have it as an SQL variable, then try something like this (note: you must declare the xsi prefix somehow - otherwise SQL Server's XML processor won't even look at your XML document):
DECLARE #input XML = '<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<student_token>7</student_token>
<student_ssn>552</student_ssn>
<alternate_id>20</alternate_id>
<old_ssn xsi:nil="true" />
.........
</row>'
;WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema-instance' as xsi)
SELECT
FieldName = T.C.value('local-name(.)', 'varchar(50)'),
FieldValue = T.C.value('(.)[1]', 'varchar(500)'),
IsNIL = ISNULL(T.C.value('(#xsi:nil)[1]', 'bit'), 0)
FROM
#Input.nodes('/row/*') AS T(C)
This gives me an output something like:
FieldName FieldValue IsNIL
student_token 7 0
student_ssn 552 0
alternate_id 20 0
old_ssn 1
.....
Of course, all output is going to be of type varchar(500) now in the FieldValue column....
Updated my answer, based on Mikael Eriksson's answer, to include the IsNIL handling, too. Thanks Mikael for the inspiration! You deserve the nod and the accept vote!
You can convert your xml file to json and then use OPENJSON instead. Take a look at openjson : SELECT star on how to use OPENJSON without having to list column names.
To convert an xml file to json you can use sp_execute_external_script and the xmltodict python module.
Take a look at Importing Python Libraries to SQL Server to import the python module and deal with YAPI (Yet Another Python Install) issues.

sp_xml_preparedocument go with error "Only one top level element is allowed in an XML document"

I'am trying to execute sp_xml_preparedocument and geting error "Only one top level element is allowed in an XML document"
my T-SQL commands:
DECLARE #aa XML
DECLARE #idoc int
SET #aa =(select * from db_name for xml auto, xmldata)
#aa now is
<Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes" name="Schema7">
<ElementType name="Person" content="empty" model="closed">
<AttributeType name="preson_id" dt:type="i4" />
<AttributeType name="Name" dt:type="string" />
<AttributeType name="Surname" dt:type="string" />
<AttributeType name="guid" dt:type="uuid" />
<AttributeType name="version" dt:type="bin.base64" />
<attribute type="preson_id" />
<attribute type="Name" />
<attribute type="Surname" />
<attribute type="guid" />
<attribute type="version" />
</ElementType>
</Schema>
<Person xmlns="x-schema:#Schema7" preson_id="1" Name="Иван" Surname="Иванов" guid="2E739E87-3CA4-4ED8-ADD0-8B59957668B8" version="AAAAAAAAB9E=" />
<Person xmlns="x-schema:#Schema7" preson_id="2" Name="Николай" Surname="Николаев" guid="BDC41C59-D70F-4B70-954E-4918B9516AF8" version="AAAAAAAAB9I=" />
<Person xmlns="x-schema:#Schema7" preson_id="3" Name="Максим" Surname="Максимов" guid="740E57F3-56BA-48B8-92AF-978D7B1D2712" version="AAAAAAAAB9M=" />
EXEC sp_xml_preparedocument #idoc OUTPUT, #aa
The XML parse error 0xc00ce555 occurred on line number 1, near the XML text ""
Msg 6602, Level 16, State 2, Procedure sp_xml_preparedocument, Line 1
The error description is 'Only one top level element is allowed in an XML document
I'am new in this, and i need help)))
An one more question - How parse timestamp type?
if i use
SET #aa =(select * from db_name for xml elements, root('root'), type)
sp_xml_preparedocument works fine, OPENXML returns all values of my db_table, but timestamp values looks not the same as were..
Sorry for my bad English
SELECT #aa returns
<Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes" name="Schema7">
<ElementType name="Person" content="empty" model="closed">
<AttributeType name="preson_id" dt:type="i4" />
<AttributeType name="Name" dt:type="string" />
<AttributeType name="Surname" dt:type="string" />
<AttributeType name="guid" dt:type="uuid" />
<AttributeType name="version" dt:type="bin.base64" />
<attribute type="preson_id" />
<attribute type="Name" />
<attribute type="Surname" />
<attribute type="guid" />
<attribute type="version" />
</ElementType>
</Schema>
<Person xmlns="x-schema:#Schema7" preson_id="1" Name="Иван" Surname="Иванов" guid="2E739E87-3CA4-4ED8-ADD0-8B59957668B8" version="AAAAAAAAB9E=" />
<Person xmlns="x-schema:#Schema7" preson_id="2" Name="Николай" Surname="Николаев" guid="BDC41C59-D70F-4B70-954E-4918B9516AF8" version="AAAAAAAAB9I=" />
<Person xmlns="x-schema:#Schema7" preson_id="3" Name="Максим" Surname="Максимов" guid="740E57F3-56BA-48B8-92AF-978D7B1D2712" version="AAAAAAAAB9M=" />
An XML document must have one root element only - see W3C specification.
Thus in you case if Schema is the root element you cannot add the Person elements at the end
Make sure that there is no duplicate entries for the record that you are trying to get

T-SQL Dynamic xquery

I am trying to figure out how I can load my table variable with data from XML using dynamic xquery? I am getting a result set of nodes from the query and defining the value type of those nodes. It seems that it is the value definition of the nodes that it is blowing up on.
Here is an example of the script that works, but is not dynamic.
Script:
DECLARE #XML XML = '<root>
<data>
<list id="organization" label="Organization">
<options>
<item value="1" label="Organization1" selected="false" />
<item value="2" label="Organization2" selected="false" />
<item value="3" label="Organization3" selected="false" />
<item value="4" label="Organization4" selected="true" />
<item value="5" label="Organization5" selected="true" />
</options>
</list>
</data>
</root>';
DECLARE #Orgs TABLE (ID INT);
Insert Into #Orgs(ID) Select OrgNameIdNodes.ID.value('#value','int') from #xml.nodes('//*[#id="organization"]//item[#selected="true"]') as OrgNameIdNodes(ID);
Select *
from #orgs
What I would like to be able to do is pass in parameters for both value and the #xml.nodes sections so I would have something like:
Insert Into #Orgs(ID) Select OrgNameIdNodes.ID.value(#Value) from #xml.nodes(#Nodes) as OrgNameIdNodes(ID);
Is this possible?
How about using sp_executesql with dynamic sql. Something like:
DECLARE #XML XML = '<root>
<data>
<list id="organization" label="Organization">
<options>
<item value="1" label="Organization1" selected="false" />
<item value="2" label="Organization2" selected="false" />
<item value="3" label="Organization3" selected="false" />
<item value="4" label="Organization4" selected="true" />
<item value="5" label="Organization5" selected="true" />
</options>
</list>
</data>
</root>';
declare #orgs table(ID int);
declare #nodes nvarchar(4000),
#value nvarchar(4000),
#query nvarchar(4000)
select #value = '''#value'',''int'''
select #nodes = '//*[#id="organization"]//item[#selected="true"]'
select #query = 'Select OrgNameIdNodes.ID.value( ' + #value + ') ' +
'from #xml.nodes(''' + #nodes + ''') as OrgNameIdNodes(ID)'
insert into #Orgs(ID) EXEC sp_executesql #query, N'#xml xml', #xml = #xml
Select *
from #orgs