Unable to get the value from SOAP Webservice Response using XMLQuery - oracle

I'm using Oracle's XMLQuery database function to read a SOAP Webservice response, however the response element "result" includes namespace clause (xmlns="http://xmlns.oracle.com/apps/hcm/processFlows/core/flowActionsService/types/") next to the element name, so the XMLQuery fails to read the element's value.
This is the Webservice response body I received, and I'm trying to read the "result"
<env:Body>
<ns0:getFlowTaskInstanceStatusResponse xmlns:ns0="http://xmlns.oracle.com/apps/hcm/processFlows/core/flowActionsService/types/">
<result xmlns="http://xmlns.oracle.com/apps/hcm/processFlows/core/flowActionsService/types/">COMPLETED</result>
</ns0:getFlowTaskInstanceStatusResponse>
</env:Body>
.
The following Select statement returns NULL
SELECT xmlcast(XMLQuery('//result' PASSING l_xmldata RETURNING CONTENT) as varchar2(900))
into l_extract
from dual;
The XMLQuery function will return "COMPLETED" in case I remove the namespace text from the XML response !!! However this is not a practical workaround.
BR
Hany

You have two options (I added an "env" namespace to make the xml valid):
include the namespaces in the query:
WITH test AS
(SELECT xmltype('
<env:Body xmlns:env="myenv">
<ns0:getFlowTaskInstanceStatusResponse xmlns:ns0="http://xmlns.oracle.com/apps/hcm/processFlows/core/flowActionsService/types/">
<result xmlns="http://xmlns.oracle.com/apps/hcm/processFlows/core/flowActionsService/types/">COMPLETED</result>
</ns0:getFlowTaskInstanceStatusResponse>
</env:Body>') AS data
FROM dual
)
SELECT CAST( extractValue(test.data, '//ns0:result','xmlns:env="myenv" xmlns:ns0="http://xmlns.oracle.com/apps/hcm/processFlows/core/flowActionsService/types/') AS VARCHAR2(900) )
FROM test
ignore the namespaces
WITH test AS
(SELECT xmltype('
<env:Body xmlns:env="myenv">
<ns0:getFlowTaskInstanceStatusResponse xmlns:ns0="http://xmlns.oracle.com/apps/hcm/processFlows/core/flowActionsService/types/">
<result xmlns="http://xmlns.oracle.com/apps/hcm/processFlows/core/flowActionsService/types/">COMPLETED</result>
</ns0:getFlowTaskInstanceStatusResponse>
</env:Body>') AS data
FROM dual
)
SELECT CAST( extractValue(test.data, '//*[local-name() = "result"]') AS VARCHAR2(900) )
FROM test

Related

XMLExists or ExistsNode: Using in WHERE clause when two XML references are used in FROM clause

I have some XML data that looks a lot like this:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<context>
<docNbr>
1234
</docNbr>
<thisType>
What I want to do, is use a table alias that ONLY selects fields from this XML if a certain type exists (I want to use XMLExists or ExistsNode when using the WHERE clause but have not been successful). This is so that I can conditionally render data between two different XML pieces. For example, I might have data that looks like this instead:
<data>
<context>
<docNbr>
1234
</docNbr>
<thatType>
Here are my two alias tables for this example:
thisType as (
SELECT x.xml_id, c.*,
'thisType' as type
FROM xml x,
XMLTABLE('//data'
PASSING x.data
COLUMNS
docNbr PATH '//context/docNumber'
WHERE XMLEXISTS('$INFO//data/context/thisType'
passing x.data as "INFO")
) c
),
thatType as (
SELECT x.xml_id, c.*,
'thatType' as type
FROM xml x,
XMLTABLE('//data'
PASSING x.data
COLUMNS
docNbr PATH '//context/docNumber'
,specialValue PATH '//moreData/subData/specialID'
WHERE XMLEXISTS('$INFO//data/context/thatType'
passing x.data as "INFO")
) c
)
The idea is to use a UNION ALL between these two tables so that one selects the other depending on which child "type" node is present.
When I try using XMLExists this way, however, I am getting a "missing right parenthesis" in my overall SQL.
Would someone be able to advise on what else I can try?
You have to put the WHERE clause in the right place.
WITH
thisType AS ( SELECT x.xml_id,
c.*,
'thisType' as type
FROM xml x,
XMLTABLE('//data'
PASSING x.data
COLUMNS
docNbr PATH '//context/docNbr'
) c
WHERE XMLEXISTS('$INFO//data/context/thisType'
PASSING x.data as "INFO")
),
thatType AS ( SELECT x.xml_id,
c.*,
'thatType' as type
FROM xml x,
XMLTABLE('//data'
PASSING x.data
COLUMNS
docNbr PATH '//context/docNbr',
specialValue PATH '//moreData/subData/specialID'
) c
WHERE XMLEXISTS('$INFO//data/context/thatType'
PASSING x.data as "INFO")
)
SELECT xml_id,
type,
docNbr,
NULL AS specialValue
FROM thisType
UNION ALL
SELECT xml_id,
type,
docNbr,
specialValue
FROM thatType;
But in my eyes it could be simpler:
SELECT x.xml_id,
c.*,
COALESCE(thisType, thatType) as type
FROM xml x,
XMLTABLE('//data'
PASSING x.data
COLUMNS
docNbr PATH '//context/docNbr',
thisType PATH '//context/thisType',
thatType PATH '//context/thatType',
specialValue PATH '//moreData/subData/specialID'
) c
Also I recommend you to name the columns and aliases better. In particular, do not use Oracle keywords.

Want to extract the a text from a tag

I have a column in a table where the data is stored in below format
<Server start>
<message tagid=" ">false</message>
<message tagid="34">no data found</message>
<message tagid=" ">false</message>
<Server stop>
Where I need to extract "no data found". Tried using regexp replace function but couldnot make it in a proper way.
Note: message tag id (number) can be of any length.
Query:
SELECT x.tagid,
x.message
FROM your_table t
CROSS JOIN
XMLTable(
'/Server/message'
PASSING XMLType(
REPLACE(
REPLACE( t.your_column, '<Server start>', '<Server>' ),
'<Server stop>',
'</Server>'
)
)
COLUMNS tagid VARCHAR2(100) PATH './#tagid',
message VARCHAR2(400) PATH './text()'
) x;
Output
TAGID MESSAGE
----- -------
false
34 no data found
false
If you just want the values where the message is no data found then add a WHERE clause at the end of the query:
WHERE x.message = 'no data found';
Try to build your query based on the following code. First converting your text to XML, then extract neccesary data by using XMLType.extract() function
with test_query as (select XMLType(replace(replace(s,'<Server stop>','</Server>'),'<Server start>','<Server>')) xml from
(select '<Server start>
<message tagid=" ">false</message>
<message tagid="34">no data found</message>
<message tagid=" ">false</message>
<Server stop>' as s from dual))
select
t.xml.extract('//message[position()=2]/text()') out
from test_query t;

Passing Date to NamedParameterJdbcTemplate in Select query to oracle

I have a query as below which is returning expected records when run from the SQL Developer
SELECT *
FROM MY_TABLE WHERE ( CRT_TS > TO_DATE('25-Aug-2016 15:08:18', 'DD-MON-YYYY HH24:MI:SS')
or UPD_TS > TO_DATE('25-Aug-2016 15:08:18', 'DD-MON-YYYY HH24:MI:SS'));
I think that we will not need to apply TO_DATE when we are passing java.util.Date object as date parameters but the below code snippet is silently returning me 0 records.
My SQL query in Java class is as below:
SELECT *
FROM MY_TABLE WHERE ( CRT_TS > :lastSuccessfulReplicationTimeStamp1
or UPD_TS > :lastSuccessfulReplicationTimeStamp2);
The code which executes the above query is as below but the below code snippet is silently returning me 0 records:
parameters.put("lastSuccessfulReplicationTimeStamp1", new java.sql.Date(outputFileMetaData.getLastSuccessfulReplicationTimeStamp().getTime()));
parameters.put("lastSuccessfulReplicationTimeStamp2", new java.sql.Date(outputFileMetaData.getLastSuccessfulReplicationTimeStamp().getTime()));
list = namedParameterJdbcTemplateOracle.query(sql, parameters, myTabRowMapper);
Please advise.
I guess you already found the answer but if anybody else needs it, here's what I've found:
java.sql.Date doesn't have time, just the date fields. Either use java.sql.Timestamp or java.util.Date. Both seems to be working for me with NamedParameterJdbcTemplate.
A little variation to above solution can be when your input(lastSuccessfulReplicationTimeStamp1/lastSuccessfulReplicationTimeStamp2) is a String instead of Date/TimeStamp (which is what i was looking for and found at this link -> may be it can help someone):
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("lastSuccessfulReplicationTimeStamp1", lastSuccessfulReplicationTimeStamp1, Types.TIMESTAMP);
parameters.addValue("lastSuccessfulReplicationTimeStamp2", lastSuccessfulReplicationTimeStamp2, Types.TIMESTAMP);
list = namedParameterJdbcTemplateOracle.query(sql, parameters, myTabRowMapper);

Dynamic sql for batch processing

I am new to MyBatis. I am trying to do a batch insert to one ORACLE db table. This is the code in XML mapper file,
<insert id="insertAuditLogAsBatch" >
insert into AUDIT_LOG (ID,ENTITY_ID,PERIOD_ID )
select SEQ_AUDIT_LOG.nextval, entityId, periodId
from
<foreach collection="auditLogs" item="auditLog">
( SELECT 1 as entityId, 1 as periodId FROM DUAL UNION ALL )
</foreach>
SELECT * FROM dual
</insert>
This is an example code and I am trying to persist hard coded values.
The above program is throwing the below error from Oracle,
; bad SQL grammar []; nested exception is java.sql.BatchUpdateException: ORA-00928: missing SELECT keyword
The generated batch SQL from my code have a "UNION ALL" at the end before closing bracket, ')'. What I need is as follows, for the last select statement I don't need 'UNION ALL' at the end. My question is,
Can I check some condition inside the foreach so that the last select will NOT have the 'UNION ALL'. instead we should have the ')' bracket to indicate the end of SELECT statements.
Does this rows insertion is batched ? I trying to test the batch operation using MyBatis here.
Complete version based on your input:
<insert id="insertAuditLogAsBatch" >
insert into AUDIT_LOG (ID,ENTITY_ID,PERIOD_ID )
select SEQ_AUDIT_LOG.nextval, entityId, periodId
from
(
<foreach collection="auditLogs" item="auditLog" open="(" separator=" UNION ALL " close=")">
SELECT 1 as entityId, 1 as periodId FROM DUAL
</foreach>
)
</insert>
try something like:
<foreach collection="auditLogs" item="auditLog" open="(" separator=" UNION ALL " close=")"> >
SELECT 1 as entityId, 1 as periodId FROM DUAL
</foreach>
Does this rows insertion is batched ? I trying to test the batch
operation using MyBatis here.
No. This is not how the batch operation works in Mybatis. For Batch insert you'll have to
1) Mention that you want the session for batch operation
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
2) Repetedly call the simple insert ( without any foreach ) for each record you want to insert
for (Foo foo: fooList)
fooDao.persistFoo(foo);
3) Flush the session after every N records
session.flushStatements();
4) Commit after all the records are inserted.
session.commit();

Set array of values to SQL query

I'm using JDBC, I have to set array of values to a single column,
I know it works in Hibernate and Ibatis but it seems to be hard to get it working Pure JDBC sql.
I have an array of String values
names[] = new String[]{"A","B","C"};
and a Query like
select * from emp where name in(?)
I tried pstmt.setObject(1,names), it is not working..
This is not supported in pure JDBC. You have to generate a query so that the in clause contains one placeholder for each element of the array.
Spring's JDBC helper classes support named parameters and what you want to do.
This will work with the following Syntax:
"SELECT * FROM emp WHERE name IN ( SELECT column_value FROM TABLE( ? ) )"
pmst.setArray( 1, conn.createArrayOf( "VARCHAR", names ) );

Resources