XQuery: Delete specific parent node based on child value - sql

I'm trying to delete a parent node from an xml document based on the value of a child node
Here's a really simplified example of what I'm looking at
<root>
<someactivity>
<id>123456789</id>
</someactivity>
</root>
What I'd like to be able to do using SQL Server / XQuery is to delete the entire 'someactivity' node and its contents by searching for the id of '123456789' in the child node 'id'.
So far I've got something like this:-
update mytablecontainingXMLcolumns
set xmldata.modify('delete //someactivity/id[text()][contains(.,"123456789")]')
but it's not working as I expected - only seems to be deleting the 'id' node. I'm stuck at this stage. Any help / guidance would be appreciated.

Modify your XPath/XQuery to be selecting the parent someactivity element instead of id :
update mytablecontainingXMLcolumns
set xmldata.modify('delete //someactivity[contains(id,"123456789")]')
or, if there can be multiple id elements within one someactivity and you want to delete the parent if, at least, one id matched :
update mytablecontainingXMLcolumns
set xmldata.modify('delete //someactivity[id[contains(.,"123456789")]]')

Related

Find XML tag which is present several times

I am working with an Oracle database 19c.
I have a table with the blob field "MSG_BODY". This field contains XML's like that:
<Body xmlns = "http://www.finnova.ch/ZV/EHF/021">
<Auftrag>
<Auftragsinformation>
<Auftragsidentifikation>
<AUF_LNR>987987987987</AUF_LNR>
<APPL_ID>9999</APPL_ID>
</Auftragsidentifikation>
<Auftragsreferenz>
<EXT_REF>TEST-2020082109574181</EXT_REF>
<EXT_AUF_REF>BA18081508D86B28</EXT_AUF_REF>
<KD_LNR_ERF>901</KD_LNR_ERF>
</Auftragsreferenz>
</Auftragsinformation>
<Zahlungsliste>
<Zahlung>
<Identifikation>
<ZV_ZLG_SYS_LNR>987987987987</ZV_ZLG_SYS_LNR>
<ZV_ZLG_LNR>1</ZV_ZLG_LNR>
</Identifikation>
<Referenz>
<EXT_REF>ABCD654654654</EXT_REF>
<EXT_REF_AUF>XX-XXX 230/99999/1</EXT_REF_AUF>
<EXT_REF_AUF_IB>BA9999988888</EXT_REF_AUF_IB>
<ZLG_INSTR_ID>BA999988886666</ZLG_INSTR_ID>
<MeldungsRef>
<MSG_TX_ID>123123123123</MSG_TX_ID>
<CS_ZLG_TRACK_ID>d8047b9f-a8c7-4d74-b5c7-470510240b60</CS_ZLG_TRACK_ID>
<CS_SWIFTGPI_SVC_ID>001</CS_SWIFTGPI_SVC_ID>
</MeldungsRef>
<MeldungsRef>
<MSG_TX_ID_DECK>xxxxxxxxxx</MSG_TX_ID_DECK>
</MeldungsRef>
</Referenz>
<Mitteilung>
<MIT_BEGxxx</MIT_BEG>
<MIT_BEG_XML>
<Ustrd>xxx</Ustrd>
</MIT_BEG_XML>
<PURP_CD>SALA</PURP_CD>
</Mitteilung>
</Zahlung>
</Zahlungsliste>
</Auftrag>
The tag "Zahlung" can exist multiple times and that's OK, but into the the tag "Zahlung" is the
tag "MeldungsRef". This tag should exist zero or one time for every tag "Zahlung". That's a fault shown in the XML above. I now need a query to select all rows in the table, which contains an XML, where the tag "MeldungsRef" is multiple times there. How can I do that?
Thanks for helping me!
Regards,
mablaser
You're looking for a second appearance of the MeldungsRef node within a Zahlung node, so you can look directly for that. This query shows you the first and second instances of the node, using xmlquery() and specifying the appearance to find with [1] or [2]:
select id,
xmlquery(
'declare default element namespace "http://www.finnova.ch/ZV/EHF/021"; (: :)
/Body/Auftrag/Zahlungsliste/Zahlung/Referenz/MeldungsRef[1]'
passing xmltype(msg_body)
returning content
) as first,
xmlquery(
'declare default element namespace "http://www.finnova.ch/ZV/EHF/021"; (: :)
/Body/Auftrag/Zahlungsliste/Zahlung/Referenz/MeldungsRef[2]'
passing xmltype(msg_body)
returning content
) as second
from your_table;
You could look for the second being not-null, but it's easier to use the same XPath with xmlexists() to test whether a second child node exists:
select id
from your_table
where xmlexists(
'declare default element namespace "http://www.finnova.ch/ZV/EHF/021"; (: :)
/Body/Auftrag/Zahlungsliste/Zahlung/Referenz/MeldungsRef[2]'
passing xmltype(msg_body)
);
db<>fiddle with one good (single node) and one bad (multiple node) row.
i receive the following error: ORA-32512: type 'xquery external variable'
As your base column is a BLOB you need to tell it which character set it's it, e.g.:
passing xmltype(msg_body, nls_charset_id('UTF8'))
db<>fiddle.

ADO.NET - Accessing Each DataView in DataViewManager

Looks like a silly question, but I can't find a way to access the DataViews in my DataViewManager.
I can see it in the DataViewManager Visualizer window, so there must be a way.
What am I doing wrong?
dvm = New DataViewManager(MyDS) ''-- MyDS is a strongly typed dataset
dvm.CreateDataView(MyDS.Company)
dvm.CreateDataView(MyDS.Sites)
MsgBox(dvm.DataViewSettings.Count) ''-- shows 7, even though I added only 2.
For Each view As DataView In dvm ''-- Error!
MsgBox(view.Table.TableName)
Next
I also observed that irrespective of how many DataViews I create, data the DataViewManager Visualizer shows all DataViews in my dataset. Why?
how do I hide those rows in parent whose child data view returns 0 rows after applying RowFilter on child
I've done it like this, but it feels like a nasty hack; I've never read the source deeply enough to know if there is a better way:
Add a column to your child datatable: Name: IsShowing, Type: Int, Expression: 1, ReadOnly: True
Put the following code:
ChildBindingSource.RemoveFilter()
ParentBindingSource.RemoveFilter()
YourDataSet.ChildDataTable.IsShowingColumn.Expression = ""
YourDataSet.ChildDataTable.Expression = $"IIF([SomeColumn] Like '{SomeFilterText}',1,0)"
ChildBindingSource.Filter = "[IsShowing] > 0"
ParentBindingSource.Filter = "Sum(Child.IsShowing) > 0"
The removal and re-add triggers a re-evaluation of the expression and the filters. There is probably a way to do this without removing/re-adding but I haven't yet found it.. Expressions are normally only re-evaluated when row data changes; changing an expression doesn't seem to recalculate all the row values/trigger a refresh of the relations and BS filters
It would be great if the parent filter supported complex expressions like SUM(IIF(Child.SomeColumn = 'SomeFilter',1,0)>0 but the SUM operator expects only a column name in the parent or child. As such, the circuitous route of having a column with an Expression be the part inside the SUM is the only way i've found to leverage the built in filtering
Remember when you test that the search is case sensitive. If you want it not to be you might have to have another column of data that is the lowercase version of what you want to search and lowercase your query string

Updating CLOB XML through updatexml

I have one tag in my table having clobe xml data like as below:
I need to update this value to 400. I am doing it as below. But its not updating. Please help.
UPDATE XYZ
SET request_xml = UPDATEXML(xmltype(request_xml),
'Parameters/Parameter[#Name="ABC"]/#Value', 400,'xmlns:n0="http://www.iQWE.com/LKJ"').getClobVal()
where transaction_id = '2017051907471800000000187725';
Your XPath doesn't make much sense. You are looking for a node called Parameter with an attribute called Name, where that attribute value is 'MaxLatenessAllowed'. There is nothing like that in your XMl document.
You can supply the full path to the node you want to change, including namespace info:
UPDATE dfxha_catchup_queue
SET request_xml = UPDATEXML(xmltype(request_xml),
'/n0:CreateOrder/n0:SalesOrders/n0:SalesOrder/n0:SalesOrderLines/n0:SalesOrderLine/n0:MaxLatenessAllowed/#Value',
400,
'xmlns:n0="http://www.i2.com/DFX"').getClobVal()
where transaction_id = '2017051907471800000000187725';
Or to shorten that you can look for that node name anywhere, if that's safe in your schema:
UPDATE dfxha_catchup_queue
SET request_xml = UPDATEXML(xmltype(request_xml),
'//n0:MaxLatenessAllowed/#Value',
400,
'xmlns:n0="http://www.i2.com/DFX"').getClobVal()
where transaction_id = '2017051907471800000000187725';
The updateXML() function is deprecated, so you might want to investigate other ways of achieving this.

SQL Server: Find records where XML is missing tag

I have table named: XMLIndex that contains a column named: XMLRec that holds the structure of an XML file and values.
Some of these records are missing a tag named: <ISO></ISO>
My question is: what type of query do I need to run in order to find all the records in the table XMLIndex, that are missing the <ISO> tag?
This is an example XMLRecord XML that contains the ISO tag:
<XMLRecord>
<pn>0042761</pn>
<SRI>4.40</SRI>
<igm>/images/images/0042761.gif</img>
<ISO>ZW</ISO>
<ListPrice>$5.50</ListPrice>
</XMLRecord>
and one with multiple ISOs (look at the tag small difference):
<XMLRecord>
<pn>0042762</pn>
<SRI>4.40</SRI>
<igm>/images/images/0042762.gif</img>
<ISOs>ZW+NZ+AU+BR</ISOs>
<ListPrice>$5.50</ListPrice>
</XMLRecord>
One record missing the ISO tag is one that the XML structure would not contain such tag.
Any examples are much appreciated.
Thank you.
You can use the XQuery exist method.
Check anywhere in the xml document:
select *
from XMLIndex
where XMLRec.exist('//ISO') = 0
Check a specific location:
where XMLRec.exist('/XMLRecord/ISO') = 0

GET url with nested element inside query string

Using Postman, I am forming a GET request query to my P21 database middleware to retrieve items with a specific value in a UserDefinedField.
I am able to query things on the top level of the item data, such as ItemID and ItemDesc like so:
http://[server]:[port]/api/inventory/parts?$query=ItemDesc eq 'CONTROL VALVE'
However, the values I would like to use in my query string are nested inside the UserDefinedFeilds element. I am specifically looking for items with:
http://[server]:[port]/api/inventory/parts?$query=UserDefinedFeilds/OnEbay eq 'Y'
But this is not the correct way to form this query string. Can anyone please explain how to specify a nested element inside a query string like this? Thanks.
In this situation, using P21 API, it is unnecessary to specify the parent field 'UserDefinedFields'. The actual ID of the column I was looking for was actually 'on_ebay', so I was able to query this user defined field simply:
http://[server]:[port]/api/inventory/parts?$query=on_ebay eq 'Y'