XML to SQL Server 2008 extract - sql-server-2008

I need further assistance with extracting records from XML and loading it into a SQL Server table.
I have this as my #xml:
<admin submitter_id="login0" effective_date="mm/dd/yyyy">
<rec effected_id="login1" adjustment="100.00" type="foo">
<reason reason_id="1" />
<reason reason_id="2" />
</rec>
<rec effected_id="login2" adjustment="50.00" type="bar">
<reason reason_id="3" />
</rec>
</admin>
I need this from a result set:
login0, login1, mm/dd/yyyy, 100.00, foo, 1
login0, login1, mm/dd/yyyy, 100.00, foo, 2
login0, login2, mm/dd/yyyy, 50.00, bar, 3
Does that make sense? The adjustment to the reason_id is one to many. I have figured out how to extract all the values except for the second line. I can only obtain the first reason_id and then it proceeds to the next record. I think this can be beaten with a CROSS APPLY but I cannot get it to work. Please help!
oh, I may also have received bogus XML. So if that's wrong, please tell me!

How about something like
DECLARE #Xml XML
SELECT #Xml = '<admin submitter_id="login0" effective_date="mm/dd/yyyy">
<rec effected_id="login1" adjustment="100.00" type="foo">
<reason reason_id="1" />
<reason reason_id="2" />
</rec>
<rec effected_id="login2" adjustment="50.00" type="bar">
<reason reason_id="3" />
</rec>
</admin>'
SELECT #Xml,
A2.B.value('(../../#submitter_id)[1]','VARCHAR(50)'),
A2.B.value('(../#effected_id)[1]','VARCHAR(50)'),
A2.B.value('(../../#effective_date)[1]','VARCHAR(50)'),
A2.B.value('(../#adjustment)[1]','FLOAT'),
A2.B.value('(../#type)[1]','VARCHAR(50)'),
A2.B.value('(#reason_id)[1]','INT')
FROM #XML.nodes('//admin/rec/reason') A2(B)
SQL Fiddle DEMO

Try to use this T-SQL code snippet:
SELECT
Submitter = #xml.value('(/admin/#submitter_id)[1]', 'varchar(50)'),
EffectedID = Rec.value('(#effected_id)[1]', 'varchar(50)'),
DateStamp = #xml.value('(/admin/#effective_date)[1]', 'varchar(50)'),
TypeID = Rec.value('(#type)[1]', 'varchar(50)'),
ReasonID = Reason.value('(#reason_id)[1]', 'int')
FROM
#xml.nodes('/admin/rec') AS Tbl(Rec)
CROSS APPLY
Rec.nodes('reason') AS T2(Reason)
It gives me an output of:
You need to have two nested lists of nodes - the first one grabs all the <rec> nodes from inside <admin>, while the second one iterates over all the <reason> nodes inside each of the <rec> nodes. That way, you can reliably extract all information from those two nested levels of subnodes, no matter how many subnodes there are on each level.

Related

Values from xml data field in mysql

i would like to know if there is a query to select values from all of my xml data fields. There are around 1k rows which has xml data. All of them has almost the same data structure. With extract value i was able to extract one data field but at the point where more than one row is part of my subquery it breaks.
Here is an example xml data inside my db:
<EDLXML version="1.0.0" type="variable">
<properties id="template_variables">
<deliveredDuration>4444</deliveredDuration>
<deliveredNum>1</deliveredNum>
<comment/>
<projectname>cdfkusen</projectname>
<name>kral_schalke_trenink</name>
<order_id>372846</order_id>
<cutlistId>2763_ID</cutlistId>
<bcutlistId>51ddgf7a6-1268-1gdfged-95e6-5254000e8e1a</bcutlistId>
<num>1</num>
<duration>177760</duration>
<quotaRelevantDuration>0</quotaRelevantDuration>
<organisationUid>OrgName</organisationUid>
<organisationQuota>333221233</organisationQuota>
<organisationUsedQuota>123</organisationUsedQuota>
<organisationContingentIrrelevantQuotaUsed>54</organisationContingentIrrelevantQuotaUsed>
<userDbId>7xxxx84-eb9b-11fdsb-9ddd1-52cccccde1a</userDbId>
<userId>xxxx</userId>
<userRights>RH_DBC</userRights>
<firstName>DThom</firstName>
<lastName>Test</lastName>
<userMail>xxx#ccc.cz</userMail>
<language>English</language>
<orderTimestamp>1659448080</orderTimestamp>
<stitching>false</stitching>
<transcode>NO</transcode>
<destination>Standard</destination>
<collaboration>private</collaboration>
<premiumUser>false</premiumUser>
<priority>normal</priority>
<userMail2>xxx#ccc.cz</userMail2>
<cutlistItems>
<cutListId>125124_KFC</cutListId>
<cutListItemId cutlistItemDeliveryStatus="&#10004" cutlistItemDStatusMessage="delivered">112799</cutListItemId>
<bmarkerId>8f16ff80-1269-11ed-95e6-5254000e8e1a</bmarkerId>
<videoId>2912799</videoId>
<counter>1</counter>
<frameInSpecified>true</frameInSpecified>
<frameIn>15638</frameIn>
<frameOutSpecified>true</frameOutSpecified>
<frameOut>20082</frameOut>
<tcIn>00:10:25:13</tcIn>
<tcOut>00:13:23:07</tcOut>
<duration>177760</duration>
<BroadcastDate>2021-07-24</BroadcastDate>
<eventDate>2021-07-24</eventDate>
<resolutionFacet>HD</resolutionFacet>
<provider>DBC</provider>
<technicalrightholders>RH_DBC</technicalrightholders>
<rights>DBC</rights>
<materialType>DP</materialType>
<targetFilename>kral_schalke_trenink</targetFilename>
</cutlistItems>
</properties>
</EDLXML>
I got the right value from query if i do:
SELECT ExtractValue((SELECT job_xml from cutlist where job_xml is not null LIMIT 1), '//deliveredNum');
But when i change the limit amount i get back: Subquery return more than one row.
extractvalue expects two string arguments. When your subquery returns more than one row, you are not simply passing a string as the first argument (you are passing a set of results).
Instead of calling extractvalue once for your entire query, call it once for every row, like:
SELECT ExtractValue(job_xml, '//deliveredNum')
FROM cutlist
WHERE job_xml IS NOT NULL

xpath filter - how to filter to the latest node record

I have an issue with filtering xpath on specified node to have only the latest record. In the example xml there s a rule that the very first record on each node is the most current information. I would like to filter all records which are not relevant (different than the first record).
The second rule is that i do not want to use date conditions to filter all job_information records after the very first one.
Normally I am using xpath tester with expression such like:
/queryCompoundEmployeeResponse/CompoundEmployee[(person/employment_information/job_information[1])]
which gives me only the first record of job information but here is does not work. Can you show me what is wrong with it?
Can you help me?
xml input with 3 job_information records
<queryCompoundEmployeeResponse>
<CompoundEmployee>
<id>11111</id>
<person>
<employment_information>
<job_information>
<end_date>9999-12-31</end_date>
<start_date>2017-05-17</start_date>
</job_information>
<job_information>
<end_date>2018-12-31</end_date>
<start_date>2017-05-17</start_date>
</job_information>
<job_information>
<end_date>2016-12-31</end_date>
<start_date>2013-05-17</start_date>
</job_information>
</employment_information>
</person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
xml output I would like to have
<queryCompoundEmployeeResponse>
<CompoundEmployee>
<id>11111</id>
<person>
<employment_information>
<job_information>
<end_date>9999-12-31</end_date>
<start_date>2017-05-17</start_date>
</job_information>
</employment_information>
</person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
Assuming you have always the same XML structure, you can try :
data=xmlParse("C:/Users/.../pathtoyourxmlfile.xml")
a=xpathSApply(data,"count(//job_information[1]/ancestor::*)+6")
b=xpathSApply(data,"count(//job_information)-1")*4+(a-1)
old=read_lines("C:/Users/.../pathtoyourxmlfile.xml")
new = old[-(a:b)]
writeLines(new,con = "new.xml")
Output (new.xml) :
<queryCompoundEmployeeResponse>
<CompoundEmployee>
<id>11111</id>
<person>
<employment_information>
<job_information>
<end_date>9999-12-31</end_date>
<start_date>2017-05-17</start_date>
</job_information>
</employment_information>
</person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>

How to retrieve a HTML tag from a column

I have an SQL table which has a column that includes some HTML/XML tag. Here is an example:
<root><Physicians><name>John Helsinki, MD</name>
<picture><img src="/uploadedImages/svr/physicians/images/John web.jpg?n=9059" alt="Helsinki, John Photo" /></picture>
<gender>M</gender>
<specialty>OPT</specialty>
<specialty2></specialty2>
<specialty3></specialty3>
<additional_specialty></additional_specialty>
</Physicians>
</root>
How can I extract the <img> tag that is in between <picture></picture>?
I know I can use the LIKE keyword in SQL but I am not sure how to proceed...
You can use XPath taking advantage of the columns type - XML
declare #thing XML
set #thing = '<root><Physicians><name>John Helsinki, MD</name>
<picture><img src="/uploadedImages/svr/physicians/images/John web.jpg?n=9059" alt="Helsinki, John Photo" /></picture>
<gender>M</gender>
<specialty>OPT</specialty>
<specialty2></specialty2>
<specialty3></specialty3>
<additional_specialty></additional_specialty>
</Physicians>
</root>'
SELECT #thing.query('/root/Physicians/picture/img')
An alternative way of doing it via a table:
DECLARE #XmlTable TABLE (ID INT NOT NULL, XmlData XML)
INSERT INTO #XmlTable
(ID, XmlData)
VALUES
(1, '<root><Physicians><name>John Helsinki, MD</name>
<picture><img src="/uploadedImages/svr/physicians/images/John web.jpg?n=9059" alt="Helsinki, John Photo" /></picture>
<gender>M</gender>
<specialty>OPT</specialty>
<specialty2></specialty2>
<specialty3></specialty3>
<additional_specialty></additional_specialty>
</Physicians>
</root>')
select XmlData.query('/root/Physicians/picture/img') from #XmlTable
This takes advantage of the query method available on any XML variable type thus in this context:
select [column].query('/root/Physicians/picture/img') from [table]

Delete xml node from SQL Server 2008 table column based on element value

I have an xml structure as follows
<ControlVisibilityRule xmlns="urn:gjensidige:processguide:201201">
<Id>e68c53a3-79ba-41e4-81cb-341050016783</Id>
<Code>b53b687c-2617-4d02-8aa0-4d0d0898bd15_Code</Code>
<Author />
<Updated>9/5/2012</Updated>
<Sequence>0</Sequence>
<FromControls>
<Control>
<Code>ada</Code>
<Id>ba2abc55-3b25-4280-8bd0-a1d23a4575d0</Id>
<FilterValues>
<FilterValue xmlns:p5="urn:gjensidige:processguide:201201" p5:Id="e2b830f8-9a58-4edf-b56c-4c5a9580f362" p5:Code="1" p5:LookupId="ebb6066f-a976-4dcb-aabe-07c4f7d2686b" />
<FilterValue xmlns:p5="urn:gjensidige:processguide:201201" p5:Id="44e268ef-2869-4df1-b61e-c59c2d3f1a5a" p5:Code="56" p5:LookupId="ebb6066f-a976-4dcb-aabe-07c4f7d2686b" />
</FilterValues>
</Control>
</FromControls>
<ToControls>
<Control>
<Code>adeUnittest01</Code>
<Id>0a1cd240-20ee-4405-9613-d3006693c390</Id>
</Control>
</ToControls>
<IsVisible>True</IsVisible>
</ControlVisibilityRule>
I want to delete the element Id in the xpath
/qn:ControlVisibilityRule/qn:ToControls/qn:Control/qn:Id
whose value is 0a1cd240-20ee-4405-9613-d3006693c390. I've done till below but I'm sure I'm missing comparison of element value with a variable.
declare #Id nvarchar(50)
declare #ruleId nvarchar(50)
;WITH XMLNAMESPACES ('urn:gjensidige:processguide:201201' as qn)
update
pdr_processdefinitionrule
set
PDR_RuleXml.modify('delete (/qn:ControlVisibilityRule/qn:ToControls/qn:Control/qn:Id=sql:variable("#Id"))')
where pdr_guid = #ruleId
Any guidance will be appreciated
You need to do this instead:
;WITH XMLNAMESPACES ('urn:gjensidige:processguide:201201' as qn)
update
pdr_processdefinitionrule
set
PDR_RuleXml.modify('delete (/qn:ControlVisibilityRule/qn:ToControls/qn:Control/qn:Id[text()=sql:variable("#Id")])')
where
pdr_guid = #ruleId
Basically, you want to delete the qn:Id element where the text() (the text that XML element contains) matches your variable #Id.

Parsing xml stored in table records in the select statement - SQL Server

I've run into a problem while trying to parse the xml which is stored in the table records
The xml structure is following :
<?xml version="1.0" encoding="utf-16"?>
<WidgetsLayout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<WidgetsList>
<WidgetConfiguration>
<WidgetId>4</WidgetId>
<DockOrder>0</DockOrder>
<DockZoneId>0</DockZoneId>
<Width />
<Height />
<IsRemovable>true</IsRemovable>
</WidgetConfiguration>
<WidgetConfiguration>
<WidgetId>3</WidgetId>
<DockOrder>0</DockOrder>
<DockZoneId>1</DockZoneId>
<Width />
<Height />
<IsRemovable>true</IsRemovable>
</WidgetConfiguration>
</WidgetsList>
</WidgetsLayout>
And the xml is stored as varchar in the table records.
I need to get the temporary table which will contain distinct set of WidgetId from the xml structure.
UPDATED :
I did write the following batch statement to retrieve the set on WidgetConfiguration xml strings, so I would be able to retrieve WidgetId set, but I've run into a problem with the insert statement:
GO
declare #dashboard_layout table (
id int,
config_xml xml
)
INSERT INTO #dashboard_layout(id)
SELECT
widget_config.value('(WidgetId)[1]', 'int')
FROM
dbo.dashboard_configuration c
CROSS APPLY
CAST(RIGHT(c.configuration_xml_string, LEN(c.configuration_xml_string) - 41), XML).nodes('/WidgetsLayout/WidgetsList/WidgetConfiguration') AS list(widget_config)
select * from #dashboard_layout
I've got an syntax error in last insert statement line when calling 'nodes' on 'cast' result
Thanks in advance.
Try this - this would work:
DECLARE #input XML = '<WidgetsLayout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<WidgetsList>
<WidgetConfiguration>
<WidgetId>4</WidgetId>
<DockOrder>0</DockOrder>
<DockZoneId>0</DockZoneId>
<Width />
<Height />
<IsRemovable>true</IsRemovable>
</WidgetConfiguration>
<WidgetConfiguration>
<WidgetId>3</WidgetId>
<DockOrder>0</DockOrder>
<DockZoneId>1</DockZoneId>
<Width />
<Height />
<IsRemovable>true</IsRemovable>
</WidgetConfiguration>
</WidgetsList>
</WidgetsLayout>'
SELECT
WList.value('(WidgetId)[1]', 'int')
FROM
#input.nodes('/WidgetsLayout/WidgetsList/WidgetConfiguration') AS Widget(WList)
So basically:
store your XML as datatype XML - or if you can't, you will have to convert your VARCHAR column to XML do to the processing
grab the list of <WidgetsLayout>/<WidgetsList>/<WidgetConfiguration> nodes as a "pseudo-table"
extract the <WidgetId> element from each of the members of that pseudo table as an INT
Update: OK, to do this from a table, use this:
INSERT INTO #dashboard_layout(ID)
SELECT
WList.value('(WidgetId)[1]', 'int')
FROM
dbo.dashboard_configuration c
CROSS APPLY
CAST(c.YourColumn AS XML).nodes('/WidgetsLayout/WidgetsList/WidgetConfiguration') AS Widget(WList)