How to iterate dblookup sql result? - wso2-esb

How do i iterate SQL result if result is more than one row.
I want read all rows values from a given table(Ex: select * from employee )
Below is the sample code.
<dblookup>
<connection>
<pool>
<password>root123</password>
<driver>com.mysql.jdbc.Driver</driver>
<url>jdbc:mysql://localhost:3306/ESB_SP_LOANS</url>
<user>root</user>
</pool>
</connection>
<statement>
<sql><![CDATA[select * from TableName]]></sql>
</statement>
</dblookup>

Have a look to https://docs.wso2.com/display/ESB500/DBLookup+Mediator
The DBLookup mediator can set a property from one row in a result set. It cannot return multiple rows

Related

Is there a way to select all elements from xmlvalue.value method instead of specifying [1]

I want to access all instances and not specify in XMLvalues.value method like 1
I have joined the nodes using outer apply but I need to specify instances number
SELECT
Id ,
XmlValues2.value('(date1)[1]', 'DateTime') AS date1 ,
XmlValues.value('(name)[1]', 'varchar(1299)') AS bank ,
XmlValues.value('(country)[1]', 'varchar(1299)') AS Country ,
FROM
Temp_board I OUTER APPLY I.board.nodes('/Report/basicInfo/report') AS xmlTableInner(XmlValues2)
OUTER APPLY XmlValues2.nodes('/Report/basicInfo/bank') AS xmlTable(XmlValues)
WHERE
Id ='235908235'
So I want the result of all nodes elements and not just the first instant
Attached screenshot of xml.I want to access all instances of transactions.XML example
For your next question please try to set up a MCVE. This is a stand along self-running example to reproduce your issue. And please do not provide code or data as pictures. This means, that somebody else has to type this in...
It is probleamtic, that the XML's picture does not inlcude the root tag and eventually existing namespaces. Furthermore, the targeted <Transaction> elements are completely empty in your picture... Furthermore, the code you provide in your question has nothing to do with the XML you show...
I think you can understand, that everything must be pure guessing and my magic crystall ball is out for cleaning at the moment ;-)
This time I do the mcve for you. A lot is just guessing to show the principles. Try this out and try to adopt it for your actual issues:
Declare a mockup-XML:
DECLARE #xml XML=
N'<SomeRootNode>
<accountList>
<Transaction SomeAttribute="blah1">
<SomeSubElement subAttr="sub1">element1</SomeSubElement>
</Transaction>
<Transaction SomeAttribute="blah2">
<SomeSubElement subAttr="sub2">element2</SomeSubElement>
</Transaction>
<Transaction SomeAttribute="blah3">
<SomeSubElement subAttr="sub3">element3</SomeSubElement>
</Transaction>
</accountList>
</SomeRootNode>';
--The query
SELECT tr.value('#SomeAttribute','varchar(100)') TheAttributeInTransactionElement
,tr.value('(SomeSubElement/#subAttr)[1]','varchar(100)') TheAttributeInTheSubElement
,tr.value('(SomeSubElement/text())[1]','varchar(100)') TheSubElementsContent
FROM #xml.nodes('/SomeRootNode/accountList/Transaction') A(tr);
The idea in short:
- .nodes() will dive into <SomeRootNode>, deeper into <accountList> and will return all <Transaction> elements found at this level
- The result of .nodes() is a derived table called A with one single XML-typed column tr, representing each Transaction in a single row.
- The .value() can pick attributes directly
- The .value() can use any kind of XPath/XQuery to fetch values from within the structure.
UPDATE Your XML has one more level Account
Try this
DECLARE #xml XML=
N'<SomeRootNode>
<accountList>
<Account>
<number>1</number>
<Transaction SomeAttribute="blah1">
<SomeSubElement subAttr="sub1">element1</SomeSubElement>
</Transaction>
<Transaction SomeAttribute="blah2">
<SomeSubElement subAttr="sub2">element2</SomeSubElement>
</Transaction>
<Transaction SomeAttribute="blah3">
<SomeSubElement subAttr="sub3">element3</SomeSubElement>
</Transaction>
</Account>
<Account>
<number>2</number>
<Transaction SomeAttribute="blah2-1">
<SomeSubElement subAttr="sub2-1">element2-1</SomeSubElement>
</Transaction>
<Transaction SomeAttribute="blah2-2">
<SomeSubElement subAttr="sub2-2">element2-2</SomeSubElement>
</Transaction>
<Transaction SomeAttribute="blah2-3">
<SomeSubElement subAttr="sub2-3">element2-3</SomeSubElement>
</Transaction>
</Account>
</accountList>
</SomeRootNode>';
SELECT acc.value('(number/text())[1]','int') AccountNumber
,tr.value('#SomeAttribute','varchar(100)') TheAttributeInTransactionElement
,tr.value('(SomeSubElement/#subAttr)[1]','varchar(100)') TheAttributeInTheSubElement
,tr.value('(SomeSubElement/text())[1]','varchar(100)') TheSubElementsContent
FROM #xml.nodes('/SomeRootNode/accountList/Account') A(acc)
OUTER APPLY A.acc.nodes('Transaction') B(tr);
Now we can use two calls to .nodes(). The first will return all <Account> elements within <accountList>, the second will return the nested <Transaction> elements as it is working with A.acc as input.

MyBatis doesn't return all the results from the query

The Problem
I have a query that returns 17 records. When I use MyBatis with a map that has an <association> it returns 6 records. Note that this doesn't happen with my other maps, I have many other maps with associations that all work fine.
Query:
with leave_counts as
(
select leave_type_id, count(llm.leave_id) as count
from lw_leave_master llm
group by leave_type_id
)
select llt.leave_type_id, llt.leave_type_abbr_tx,
llt.leave_type_desc_tx, lc.count as count_nm
from lw_leave_type llt
join leave_counts lc on lc.leave_type_id=llt.leave_type_id
order by llt.leave_type_abbr_tx
Map:
<resultMap id="typeCountMap" type="mypackage.myclass">
<result property="count" column="count_nm"/>
<association property="type" resultMap="package.myMap"/>
</resultMap>
<resultMap id="myMap" type="mypackage.myclass2">
<result property="id" column="leave_type_id"/>
<result property="abbr" column="leave_type_abbr_tx"/>
<result property="description" column="leave_type_desc_tx"/>
</resultMap>
The <association> in typeCountMap refers to the map myMap.
This returns 6 records every time. Grabbing the actual query run from the logger and running it manually returns 17 records.
Solutions?
There are two things I can do to get MyBatis to return all 17 records
#1
If I remove the lc.count as count_nm from my query I get all 17 records returned (just with no values associated with them)
with leave_counts as
(
select leave_type_id, count(llm.leave_id) as count
from lw_leave_master llm
group by leave_type_id
)
select llt.leave_type_id, llt.leave_type_abbr_tx,
llt.leave_type_desc_tx
from lw_leave_type llt
join leave_counts lc on lc.leave_type_id=llt.leave_type_id
order by llt.leave_type_abbr_tx
This is obviously not a good solution, but I wanted to include this in case it would help you figure out what I'm doing wrong.
#2
If I replace the association with the contents of the other map everything works as expected.
<resultMap id="typeCountMap" type="mypackage.myclass1">
<result property="count" column="count_nm"/>
<result property="type.id" column="leave_type_id"/>
<result property="type.abbr" column="leave_type_abbr_tx"/>
<result property="type.description" column="leave_type_desc_tx"/>
</resultMap>
This obviously is what I'll do if I don't find another solution, since this does work. It would just be nice to use the <association> like I have in other maps.
I should note that I am using MyBatis 3.1.1
I recently ran into this same problem. I believe the issue was related to my main resultMap with the association in it not having an id column while my association's resultMap did have an id column. My results were getting grouped by the associations id column.
To correct the issue I selected the row number in my query and added an id to my main resultMap pointing to the row number column.
If you're using 3.1.1 you can define just <id column="leave_type_id" /> without property attribute
If you're not using 3.1.1 you can add <result property="abbr" column="leave_type_id" /> on top of the list to include field into cache key calculation for association, later re-definition will assign correct value
I don't know if this is the problem, but it's something to try. I have to post here because I don't have enough rep to leave a comment.
Try adding a column attribute to your association and marking the ID column in the second map:
<resultMap id="typeCountMap" type="mypackage.myclass">
<result property="count" column="count_nm"/>
<association property="type" column="leave_type_id" resultMap="package.myMap"/>
</resultMap>
<resultMap id="myMap" type="mypackage.myclass2">
<id property="id" column="leave_type_id"/>
<result property="abbr" column="leave_type_abbr_tx"/>
<result property="description" column="leave_type_desc_tx"/>
</resultMap>
You should replace the line <result property="id" column="leave_type_id"/>
with <id property="id" column="leave_type_id"/>.
In mybatis you should not miss to specify the id column it may mess up with your result set.

Extracting XML data in SQL - too many cross apply statements

I have an xml document containing details from a Statement:
<Statement>
<Id />
<Invoices>
<Invoice>
<Id />
<Date />
<AmountDue />
etc.
</Invoice>
<Invoice>
<Id />
<Date />
<AmountDue />
etc.
</Invoice>
<Invoice>
<Id />
<Date />
<AmountDue />
etc.
</Invoice>
</Invoices>
</Statement>
This works fine for the Statement specific details:
SET #statementId = #xml.value('(Id)[1]', 'UNIQUEIDENTIFIER');
but it requires a singleton, and only returns the first value. I need ALL of the values for the invoices, not just the first so a singleton won't work.
I am able to get the information out using cross apply statements like this:
SELECT
#statementId AS STATEMENT_ID
Id.value('.', 'uniqueidentifier') AS INVOICE_ID
Date.value('.', 'smalldatetime') AS INVOICE_DATE
Due.value('.', 'decimal') AS INVOICE_AMOUNT_DUE
FROM #xml.nodes('Statement') A(S)
cross apply S.nodes('Invoices/Invoice') B(InvoiceD)
cross apply InvoiceD.nodes('Id') C(Id)
cross apply InvoiceD.nodes('Date') D(Date)
cross apply InvoiceD.nodes('AmountDue') E(Due)
This returns an Id, date, and amount from each Invoice in the Statement - perfect.
My problem comes when I try to extract all of the invoice details. I currently have seven cross apply statements and I got the following message:
"The query processor ran out of internal resources and could not
produce a query plan. This is a rare event and only expected for
extremely complex queries or queries that reference a very large
number of tables or partitions. Please simplify the query. If you
believe you have received this message in error, contact Customer
Support Services for more information."
What I want to do is have one cross apply for the Invoice and narrow down the exact field in the select statement, but unless I use '.' I must make the statement return a singleton and I don't get all of the data that I need.
I have done some research about specifying a namespace within the select statement, but all of the examples set the namespace to be an http address instead of a node in an xml document and I haven't gotten anything to return yet using this approach.
The result I'm looking for is something like this, but with more Invoice Details:
STATEMENT_ID INVOICE_ID INVOICE_DATE INVOICE_AMOUNT_DUE ...
Statement-1-Id Invoice-1-Id Invoice-1-Date Invoice-1-AmountDue ...
Statement-1-Id Invoice-2-Id Invoice-2-Date Invoice-2-AmountDue ...
Statement-1-Id Invoice-3-Id Invoice-3-Date Invoice-3-AmountDue ...
Where should I go from here?
EDIT: I removed some unnecessary information. Getting all of the invoice-specific details is my goal here.
select #XML.value('(Statement/Id/text())[1]', 'uniqueidentifier') as StatementId,
T.N.value('(Id/text())[1]', 'uniqueidentifier') as InvoiceId,
T.N.value('(Date/text())[1]', 'smalldatetime') as InvoiceDate,
T.N.value('(AmountDue/text())[1]', 'decimal') as AmountDue
from #XML.nodes('/Statement/Invoices/Invoice') as T(N)
.nodes will shred your XML to rows so that each row T.N is pointing to an Invoice node of its own. On that node there is only a single Id node so fetching the value specifying a singleton Id[1] works.
You can use Id[1] or (Id/text())[1] but the latter will give you a more efficient execution plan.

Finding the relevant records using XQuery/XPath

I'm very very new to XQUERY/XPATH :) so I could very well be going about this the wrong way. I have a customer object serialized and stored in a database column in the following format.
<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Addresses>
<AddressBlock>
<AddressLine1>1234 SomeStreet Ave.</AddressLine1>
<City>SomeCity</City>
<State>SomeState</State>
<Zipcode>SomeZip</Zipcode>
</AddressBlock>
<AddressBlock>
<AddressLine1>5678 SomeOtherStreet Ave.</AddressLine1>
<City>SomeOtherCity</City>
<State>SomeOtherState</State>
<Zipcode>SomeOtherZip</Zipcode>
</AddressBlock>
</Addresses>
</Customer>
I'm looking for a way to select this record if addressline1 and city in the same addressblock contains certain keywords. I have the following statement that almost does what I'm looking for.
select *
from users
where [UserData].exist('/Customer/Addresses/AddressBlock/AddressLine1/text()[contains(upper-case(.),""SOMESTREET"")]')=1
and [UserData].exist('/Customer/Addresses/AddressBlock/City/text()[contains(upper-case(.),""SOMECITY"")]')=1"
My only problem is this statment will also return the record if the first addressblock contains the addressline1 and the second addressblock contains the city.
You have to test both conditions in the same XQuery.
select *
from users
where [UserData].exist('/Customer/Addresses/AddressBlock
[contains(upper-case(AddressLine1[1]),"SOMESTREET") and
contains(upper-case(City[1]),"SOMECITY")]')=1

XML & YQL (similar to SQL) - how to get a subnode's attribute?

I'm trying to select a certain set of data with YQL, but I'm confused on how to get to sublevels with my YQL. For example, if I run this query:
select * from music.track.search where keyword="Asia"
I get this:
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="22" yahoo:created="2011-07-07T16:47:41Z" yahoo:lang="en-US">
<results>
<Track discNumber="1" duration="0" explicit="0" flags="0"
id="61642071" label="Mark Saliba" popularity="3" rating="-1"
releaseYear="2008" rights="2208" title="Asia"
trackNumber="3" url="http://new.music.yahoo.com/mark-j-saliba/tracks/asia--61642071">
<Artist catzillaID="0" flags="2" hotzillaID="0"
id="205843271" name="Mark J Saliba" rating="-1"
trackCount="11"
url="http://new.music.yahoo.com/mark-j-saliba/" website=""/>
<Album>
and if I run this query:
select ID from music.track.search where keyword="Asia"
I get this:
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng"
yahoo:count="22" yahoo:created="2011-07-07T16:50:13Z" yahoo:lang="en-US">
<results>
<Track id="61642071"/>...
But what I want to do is just get the artist IDs, not the track IDs (specifically, just the first result would be fine). What is the YQL statement for that?
For all artist ids:
select Artist.id from music.track.search where keyword="Asia"
For just the first artist id:
select Artist.id from music.track.search where keyword="Asia" limit 1