XQuery how to get whole xml document with WHERE query - xquery

I have XML db with only one collection (container) and I don't know the document names. How to get a entire XML document from db, which complies WHERE clause?
<root>
<node1>
<node2>
<node3>My Content</node2>
</node2>
</node1>
<root>
When I have queries
query 'collection("data1.dbxml")/root/node1/node2[node3 = "My Content"]/string()'
it returns a content from that node3
'My Content'
and
query 'collection("data1.dbxml")/root/ode1/node2/node3'
it returns 2 internal nodes with the content
<node2><node3>My Content</node3></node2>
But how to get whole document which complies this WHERE clause (sth like SELECT * FROM data2.dbxml WHERE node3='My Content'?

Simply use a predicate as you did in the first example:
collection("data1.dbxml")/root[node1/node2/node3 = "My Content"]
You can think of the predicate in XQuery as the WHERE in SQL and the SELECT-part is everything before.

another resolution ... after studying :)
query 'for $x in collection("data1.dbxml")
where $x/root/node1/node2/node3 = "My Content"
return $x'
or when we know the depth of node in XMLdoc and node's name
query 'for $x in collection("data1.dbxml")
where $x/*/*/*/node3 = "My Content"
return $x'
thanks W3Schools

Related

How do I sort by names or postcodes using a drop-down list to determine what to sort by?

Currently, I am trying to create some software on Progress OpenEdge that sorts by customer's names or account codes.
So essentially, a box will open up when the program runs, the user will select "Name" from the drop-down list, and the program will display all the names in the database from alphabetical order.
Or, they will pick "Account" from the drop-down list, and it will display all the account codes in numeric order. I have attached a picture of the program here:
And this is currently the code I am using to print the results:
However, I'm not sure what I need to add for the others. Would I need IF statements, such as:
OR IF [drop down list] = "Account" THEN or something like that?
Any help would be appreciated.
While you can perform a static order by with a convulted set of if statements, it is a lot cleaner with a dynamic query.
To expand on Tom and Stefan's answers, you can use a query. The ABL lets you create a lot of things with static constructs and use them as dynamic. I think that in this case, you want to so something like the below.
Note that you can do build the query string either using OPEN QUERY qry FOR EACH ... or QUERY qry:QUERY-PREPARE('FOR EACH ... ') ; both will work equally well.
What I think you'd want is
(a) having a static definition of the query (ie DEFINE QUERY) since the cost of adding the buffer(s) to the query is done at compile time, not run time, and
(b) accessing the buffer fields statically (ie slmast.name rather than b::name )
define query qry for slmast.
define variable wc as character no-undo.
if condition eq true then
wc = "WHERE kco = s-kco AND warecode = lv-warecode AND pcode = fi-pcode AND name = fi-name BY name".
else
wc = "WHERE TRUE".
/* alternate
if condition then
open query qry for each slmast no-lock WHERE kco = s-kco AND warecode = lv-warecode AND pcode = fi-pcode AND name = fi-name BY name.
else
open query qry for each slmast no-lock.
*/
query qry:query-prepare(wc).
open query qry.
query qry:get-first().
do while available slmast:
/* do stuff with the buffer */
{&OUT} slmast.name.
query qry:get-next().
end.
query qry:query-close().
Using static constructs as far as possible means that you have less cleanup code to write and the code becomes more readable (IMO).
There are multiple ways to loop through the query results: using DO WHILE NOT QUERY qry:QUERY-OFF-END works as well as AVAILABLE slmast or b:AVAILABLE (if using a purely dynamic query).
As Stefan says, a dynamic query is what you want. This might help get you started:
define variable wc as character no-undo.
define variable q as handle no-undo.
define variable b as handle no-undo.
/* run your UI to get selection criteria amd then
* create a WHERE clause as appropriate
*/
wc = "WHERE kco = s-kco AND warecode = lv-warecode AND pcode = fi-pcode AND name = fi-name BY name".
create buffer b for table "slmast".
create query q.
q:set-buffers( b ).
q:query-prepare( substitute( "FOR EACH slmast NO-LOCK &1", wc )).
q:query-open().
do while q:get-next():
display
b:buffer-field( "name" ):buffer-value
b:buffer-field( "acode" ):buffer-value
b:buffer-field( "pcode" ):buffer-value
b:buffer-field( "trunmtd" ):buffer-value
b:buffer-field( "turnytd" ):buffer-value
.
end.

ibm bpm - execute sql statement return type

how to manage the result of a query that returns an integer "select count(*) from table"?
1) I've tried to bind the output of a SQL Execute Statement service to an integer variable and doesn't work. (type mistmatch)
2) i've tried to use types like 'SQLResult', SQLResultRow, SQLResultColumn as well but they dont work:
Caused by: com.lombardisoftware.core.TeamWorksException: Type ismatch the value "[Element: ]" must be and instance of type atructured IBM BPM Java Class found: org.jdom.Element
3) i've tried to bind the output to a XMLElement variable and i've got this value
< resultSet recordCount=\"1\" columnCount=\"1\">5< /columnn>< /record>< /resultSet>
so now... how can I access the recordCount attribute of this node?
anyway, I don't like so manipulate a variable of XMLType, when are the types SQLResult, SQLResultRow, SQLResultColumn used?
****** EDITED *******
even if i get a result as XMLElement.. i can't manipulate it.
methods like: tw.local.result[0].rows[0].column[0].getText() don't work (the intellisense as well)
the XMLElement as an attribute "recordCount" but i don't know how to get his value..
Anyway, the only workaround that i found is to change the query in order to return a normal set of records(not a scalar value)
select field from table instead of select count(field) from table
so i could to map the output value to a list of objects and than count its length...
ugly and dirty :-(
anyone know how manipulate the XMLElement in a script block?
Please try this.
Bind the output variable from sql execute statement as 'ANY' type.
variable name - result (ANY)
Query - select count(field) as COUNTVAL from table
tw.local.totalCount = tw.local.result[0].rows[0].indexedMap.COUNTVAL;
Use Return type as XMLElement then bind a XMLElement in output mapping.
For eg: If you are using tw.local.output as ouput mapping (of type XMLElement) then,
log.info("Count "+tw.local.output.xpath('/resultSet/record/column').item(0).getText());
This will print the count
If you want to get "recordCount" Attribute then use
tw.local.output.getAttribute("recordCount");

How to remove collection or edge document using for loop in ArangoDB?

I'm using the latest ArangoDB 3.1 on Windows 10.
Here I want to remove the collection document and edge document using the for loop. But I'm getting an error like document not found (vName).
vName contains the many collection names. But I dunno how to use it in for loop.
This is the AQL I am using to remove the documents from the graph:
LET op = (FOR v, e IN 1..1 ANY 'User/588751454' GRAPH 'my_graph'
COLLECT vid = v._id, eid = e._id
RETURN { vid, eid }
)
FOR doc IN op
COLLECT vName = SPLIT(doc.vid,'/')[0],
vid = SPLIT(doc.vid,'/')[1],
eName = SPLIT(doc.eid,'/')[0],
eid = SPLIT(doc.eid,'/')[1]
REMOVE { _key: vid } in vName
Return output im getting from the AQL (Web UI screenshot)
vName is a variable introduced by COLLECT. It is a string with the collection name of a vertex (extracted from vid / v._id). You then try to use it in the removal operation REMOVE { ... } IN vName.
AQL does not support dynamic collection names however, collection names must be known at query compile time:
Each REMOVE operation is restricted to a single collection, and the collection name must not be dynamic.
Source: https://docs.arangodb.com/3.2/AQL/Operations/Remove.html
So, you either have to hardcode the collection into the query, e.g. REMOVE { ... } IN User, or use the special bind parameter syntax for collections, e.g. REMOVE { ... } IN ##coll and bind parameters: {"#coll": "User", ...}.
This also means that REMOVE can only delete documents in a single collection.
It's possible to workaround the limitation somewhat by using subqueries like this:
LET x1 = (FOR doc IN User REMOVE aa IN User)
LET x2 = (FOR doc IN relations REMOVE bb IN relations)
RETURN 1
The variables x1 and x2 are syntactically required and receive an empty array as subquery result. The query also requires a RETURN statement, even if we don't expect any result.
Do not attempt to remove from the same collection twice in the same query though, as it would raise a access after data-modification error.

XQuery : OBJECT_VALUE invalid identifier

I've created a table
Movie ( title varchar2(40), review XMLTYPE)
And review has: `
<review>
<reviewer>...</reviewer>
<title> ....</title>
<rating>.....</rating> </Review> </reviewer>
When I try to access :
SELECT X.reviewername FROM movie m, XMLTABLE ('for $d in /reviews/review
return $d'
PASSING OBJECT_VALUE
columns
reviewername VARCHAR2(50) PATH 'reviewer') AS X
I get an error at OBJECT_VALUE. Where am I going wrong?
EDIT: I changed the Query to
SELECT m.title,
warehouse2.*
FROM movie M,
XMLTABLE('/REVIEW'
PASSING m.reviews
COLUMNS
"Rail" varchar2(60) PATH '//RATING')
warehouse2;
But no rows are getting selected. Any suggestions?
Well for one thing, don't you have a typo: '/reviews/review ' ? there is no element called anywhere in your example.
Your XML isn't well formed, you have overlapping tags, you have mismatched reviews/Reviews (XML is case sensitive) and in your query you have reviews/review but your xml has /review (no s on the end). –

EntityFramework using with database foreign key

Actually I spend whole day on the EntityFramework for foreign key.
assume we have two table.
Process(app_id,process_id)
LookupProcessId(process_id, process_description)
you can understand two tables with names, first table ,use process_id to indicate every application, and description is in the seoncd table.
Actually i try many times and figure out how to do inquery: it was like
Dim result = (from x in db.Processes where x.LookupProcess is (from m in db.LookupProcessIds where descr = "example" select m).FirstOrDefault() select x).FirstOrDefault()
First I want to ask is there easier way to do it.
Second i want to ask question is about insert
p As New AmpApplication.CUEngData.Process
p.app_id=100
p.LookupProcess = (from m in db.LookupProcessIds where descr = "example" select m).FirstOrDefault()
db.AddToProcesses(p)
db.SaveChanges()
from appearance it looks fine, but it give me error says
Entities in 'AmpCUEngEntities.Processes' participate in the 'FK_Process_LookupProcess' relationship. 0 related 'LookupProcess' were found. 1 'LookupProcess' is expected.
can i ask is that insert wrong? and is that my query correct?
For your first question:
Dim result = (from x in db.Processes
where x.LookupProcess.descr = "example"
select x).FirstOrDefault()
Actually, you missed some concepts from DataEntityModel, and its Framework. To manipulate data, you have to call object from contextual point of view. Those allow you to specify to the ObjectStateManager the state of an DataObject. In your case, if you have depending data from FK, you will have to add/update any linked data from leaf to root.
This example demonstrate simple (no dependances) data manipulation. A select if existing and an insert or update.
If you want more info about ObjectStateManager manipulation go to http://msdn.microsoft.com/en-us/library/bb156104.aspx
Dim context As New Processing_context 'deseign your context (this one is linked to a DB)
Dim pro = (From r In context.PROCESS
Where r.LOOKUPPROCESS.descr = LookupProcess.descr
Select r).FirstOrDefault()
If pro Is Nothing Then 'add a new one
pro = New context.PROCESS With {.AP_ID = "id", .PROCESS_ID = "p_id"}
context.PROCESS.Attach(pro)
context.ObjectStateManager.ChangeObjectState(pro, System.Data.EntityState.Added)
Else
'update data attibutes
pro.AP_ID = "id"
pro.PROCESS_ID = "p_id"
context.ObjectStateManager.ChangeObjectState(pro, System.Data.EntityState.Modified)
'context.PROCESS.Attach(pro)
End If
context.SaveChanges()
I hope this will help. Have a nice day!
For your first question, to expand on what #jeroenh suggested:
Dim result = (from x in db.Processes.Include("LookupProcess")
where x.LookupProcess.descr = "example"
select x).FirstOrDefault()
The addition of the Include statement will hydrate the LookupProcess entities so that you can query them. Without the Include, x.LookupProcess will be null which would likely explain why you got the error you did.
If using the literal string as an argument to Include is not ideal, see Returning from a DbSet 3 tables without the error "cannot be inferred from the query" for an example of doing this using nested entities.
For your second question, this line
p.LookupProcess = (from m in db.LookupProcessIds
where descr = "example" select m).FirstOrDefault()
Could cause you problems later on because if there is no LookupProcessId with a process_description of "example", you are going to get null. From MSDN:
The default value for reference and nullable types is null.
Because of this, if p.LookupProcess is null when you insert the entity, you will get the exception:
Entities in 'AmpCUEngEntities.Processes' participate in the 'FK_Process_LookupProcess' relationship. 0 related 'LookupProcess' were found. 1 'LookupProcess' is expected.
To avoid this kind of problem, you will need to check that p.LookupProcess is not null before it goes in the database.
If Not p.LookupProcess Is Nothing Then
db.AddToProcesses(p)
db.SaveChanges()
End If

Resources