I have following xml in my table. I want to get ID of a fv node:
<fv ID="Description"> or not
<DataFormItem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="bb_appfx_dataforms">
<Values>
<fv ID="JobInterval">
<Value xsi:type="xsd:int">10</Value>
</fv>
<fv ID="JobEnabled">
<Value xsi:type="xsd:boolean">false</Value>
</fv>
<fv ID="JobName">
<Value xsi:type="xsd:string">Default transactional email process</Value>
</fv>
<fv ID="ScheduleFrequencySubDayType">
<Value xsi:type="xsd:int">2</Value>
</fv>
</Values>
</DataFormItem>
Assuming your table is called YourTable and the XML column is called XmlData (adapt and change this to meet your actual situation!), you can try this XQuery code:
-- declare the XML namespace as the DEFAULT
;WITH XMLNAMESPACES(DEFAULT 'bb_appfx_dataforms')
SELECT
-- extract the value from the <Value> subnode of the <fv> node, if found
FvValue = XC.value('(Value)[1]', 'varchar(200)')
FROM
dbo.YourTable
CROSS APPLY
-- get a list of XML fragments - one for each <fv> node
XmlData.nodes('/DataFormItem/Values/fv') AS XT(XC)
WHERE
-- find the XML fragment with the ID="Description"
XC.value('#ID', 'varchar(50)') = 'Description'
Related
I'm working on migrating some codes from MSSQL to MySQL, but I don't know the equivalent of local-name()in MySQL.
The original MSSQL code is as followed:
with cte as (select convert(xml,'<Attributes>
<Map>
<entry key="trigger" value = "action">
<value>
<Map>
<entry key=" Processing">
<value>
<Boolean>true</Boolean>
</value>
</entry>
</Map>
</value>
</entry>
</Map>
</Attributes>') as attributes)
select entr.value('#key','nvarchar(100)') AS AttrKey
,entr.value('#value','nvarchar(500)') AS AttrValue
,HasValueElement.value('local-name(.)','nvarchar(100)') AS ValueType
FROM cte a1
cross apply a1.attributes.nodes(N'/Attributes/Map/entry') A(entr)
OUTER APPLY A.entr.nodes(N'value/*') B(HasValueElement)
The output is:
AttrKey ||AttrValue ||ValueType
Trigger ||Action ||Map
How we can apply similar to local-name() in MySQL to return the ValueType = "Map"? When I tried something like "//*[local-name()]" in MySQL, it returned error.
And what is the "." in "local-name(.)" meaning?
Really appreciate your support.
TIA
Apparently I have a field call Data which store some xml node + json inside the those node.
I can retrieve the deliveryID by using:
JSON_VALUE(ml.Data.value('(/row/value)[2]', 'NVARCHAR(MAX)'),'$.transactions[0].deliveryId') deliveryID
However, the transactions might not always be at the second node of it,
it can be on any row.
Is there any other way I can do to iterate the node and find if it has a json transactions inside then get the deliveryID from the row?
Thanks
<row>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="eb71fd46-f0b2-401d-9775-08d4d90ab608" display-name="Card_Number">3083 2614 5022 21321</value>
<value id="4fc261b2-f776-4fd4-8e1d-08d4d90ab608" display-name="Email_Address">jello#anc.com</value>
<value id="c867d4e5-cc0b-4ee6-b911-08d6134132e0" display-name="BP_TRIGGERS_2.0">{"transactions":[{"BP_CommsRef":"V0001","BP_Offer_Expiry":"2018-10-01T00:00:00","deliveryId":"20320925","Job_Number":"A34F443","Send_Date":"2018-09-26T00:00:00"}]}</value>
</row>
If I get you correctly, you want to find a JSON within your <value> elements and read the deliverId from there:
Declare #XML xml = '
<row>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="eb71fd46-f0b2-401d-9775-08d4d90ab608" display-name="Card_Number">3083 2614 5022 21321</value>
<value id="4fc261b2-f776-4fd4-8e1d-08d4d90ab608" display-name="Email_Address">jello#anc.com</value>
<value id="c867d4e5-cc0b-4ee6-b911-08d6134132e0" display-name="BP_TRIGGERS_2.0">{"transactions":[{"BP_CommsRef":"V0001","BP_Offer_Expiry":"2018-10-01T00:00:00","deliveryId":"20320925","Job_Number":"A34F443","Send_Date":"2018-09-26T00:00:00"}]}</value>
</row>';
--This will check for an opening { (you could search for an opening {"transactions" as well)
SELECT JSON_VALUE(
#XML.query(N'/row/value[substring(text()[1],1,1)="{"]/node()')
.value(N'text()[1]','nvarchar(max)')
,N'$.transactions[0].deliveryId');
--The same approach but looking at the attribute display-name
SELECT JSON_VALUE(
#XML.query(N'/row/value[#display-name="BP_TRIGGERS_2.0"]/node()')
.value(N'text()[1]','nvarchar(max)')
,N'$.transactions[0].deliveryId');
The idea in short: .query() the XML for a <value> below <row>, which fullfills the filter. Take this node() and read the .value() from there.
This is handed into JSON_VALUE in order to retrieve the needed deliveryId.
You can do the same with the attribute id and you can hand in the values with a declard variable (sql:variable()) or from a column in your result-set (sql:column()).
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.
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.
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)