Dynamic sql for batch processing - oracle

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();

Related

Select Statement Using Dual Table As A Sub Query In Oracle Generates "From keyword not found" Error

I get below error message while executing following queries using a select statement from dual table as a sub query:
Error: ORA-00923: FROM keyword not found where expected
Query 1:
select a.dt_1, a.dt_2, a.dt_1=a.dt_2 as "match_type" from
(select to_date(replace('2020-05-14 00:00:00',' 00:00:00',''), 'yyyy/mm/dd') as "dt_1", to_date('14/05/2020','dd/mm/yyyy') as "dt_2" from dual) a
Query 2:
select a.dt_1, a.dt_2, a.dt_1=a.dt_2 as match_type from
(select to_date(replace('2020-05-14 00:00:00',' 00:00:00',''), 'yyyy/mm/dd') as dt_1, to_date('14/05/2020','dd/mm/yyyy') as dt_2 from dual) a
When I individually run sub query it executes as expected, however when I run the whole statement it generates error.
Any help is appreciated.
Your match_type column is generating the error. Oracle doesn't support relational operator matching. You may try below query -
SELECT a.dt_1,
a.dt_2,
CASE WHEN a.dt_1=a.dt_2 THEN 'TRUE' ELSE 'FLASE' END AS "match_type"
FROM (SELECT TO_DATE(REPLACE('2020-05-14 00:00:00',' 00:00:00',''), 'yyyy/mm/dd') as "dt_1",
TO_DATE('14/05/2020','dd/mm/yyyy') as "dt_2"
FROM DUAL) a;

FOR LOOP Statement in BigQuery

I have data in two tables:
Table activity:
User_ID Event_Time Cmd
AMsySZb9GPcL 1512125190721078 1
AMsySZYQ-lAI 1512118629594674 0
AMsySZZMlPzD 1512125736366076 1
....
Table behaviour:
User_ID Event_Time
AMsySZZFezm 1512145788526664
AMsySZb9GPcL 1512125190721078
AMsySZY5YcTa 1512143509733637
AMsySZYQ-lAI 1512118629594674
AMsySZZMlPzD 1512125736366076
....
User_ID is type STRING, Event_Time is type INTEGER.
Step 1: The basic SELECT statement I am making now is:
SELECT activity.User_ID, activity.Event_Time FROM activity WHERE Cmd=1
Step 2: Then I would like to get data from behaviour table, but only for Users from Step 1 and only where behaviour.Event_Time is before activity.Event_Time.
For example:
From Step 1 I got User_ID='AMsySZb9GPcL' and I need:
SELECT behaviour.User_ID, behaviour.Event_Time
FROM behaviour
WHERE User_ID='AMsySZb9GPcL' AND activity.Event_Time >= behaviour.Event_Time
But the problem is that I have to do the same for every User_ID from Step 1, I am not sure if it is the supported functionality of SQL, but I need something like FOR LOOP.
You don't need FOR LOOP for this - you should think of set based operation when you deal with SQL of any sort - so you can process all your users in one shot using power of JOINs
Below is for BigQuery Standard SQL
#standardSQL
SELECT
activity.User_ID User_ID,
activity.Event_Time activity_Time,
behaviour.Event_Time behaviour_Time
FROM `project.dataset.activity` activity
JOIN `project.dataset.behaviour` behaviour
ON activity.User_ID = behaviour.User_ID
AND activity.Event_Time >= behaviour.Event_Time
WHERE Cmd = 1
You can test / play with above using dummy data from your example:
#standardSQL
WITH `project.dataset.activity` AS (
SELECT 'AMsySZb9GPcL' User_ID, 1512125190721078 Event_Time, 1 Cmd UNION ALL
SELECT 'AMsySZYQ-lAI', 1512118629594674, 0 UNION ALL
SELECT 'AMsySZZMlPzD', 1512125736366076, 1
), `project.dataset.behaviour` AS (
SELECT 'AMsySZZFezm ' User_ID, 1512145788526664 Event_Time UNION ALL
SELECT 'AMsySZb9GPcL', 1512125190721078 UNION ALL
SELECT 'AMsySZY5YcTa', 1512143509733637 UNION ALL
SELECT 'AMsySZYQ-lAI', 1512118629594674 UNION ALL
SELECT 'AMsySZZMlPzD', 1512125736366076
)
SELECT
activity.User_ID User_ID,
activity.Event_Time activity_Time,
behaviour.Event_Time behaviour_Time
FROM `project.dataset.activity` activity
JOIN `project.dataset.behaviour` behaviour
ON activity.User_ID = behaviour.User_ID
AND activity.Event_Time >= behaviour.Event_Time
WHERE Cmd=1

(iBatis) I want to insert multiple data list in a table

I develop web application using Spring and iBatis. I want to insert multiple data in a table. I throw DataMap including ArrayList in controller as follow.
param.put("aList", aList);
param.put("aaaSeq", aaaSeq);
commonDAO.insert(namespace, "insertAAA", param);
In ibatis,
<insert id="insertAAA" parameterClass="dmap">
<selectKey keyProperty="aaaSeq" resultClass="java.lang.Integer" type="pre">
SELECT a_seq.nextval FROM DUAL
</selectKey>
insert into AAA
(
aSeq,
a,
)
<iterate property="aList" open="(" close=")" conjunction=" union all ">
select
#aaaSeq#,
#aList[]#
from
dual
</iterate>
</insert>
However, it have an error related with Integrity Constraints.
So, I wondering how to insert multiple data in a single table.

ORA-00928 selecting from view over DB link, but works locally

I have a view with a query of the following form which works perfectly when I query it on the local server from any schema:
WITH dates AS (
SELECT /*+ materialize */ ... FROM ( SELECT ... FROM table#link)
UNION ALL
SELECT * FROM ( SELECT /*+ materialize */ FROM table#link )
)
SELECT ... FROM (
SELECT ... FROM (
SELECT ... FROM (
SELECT ... FROM (
SELECT ... FROM
)
) foo
LEFT OUTER JOIN (
SELECT /*+ USE_MERGE(hle dates) */ ... FROM
) bar ON conditions
)
)
UNION ALL
SELECT ... FROM (
SELECT ... FROM (
SELECT ... FROM (
SELECT ... FROM (
SELECT ... FROM
)
) foo
LEFT OUTER JOIN (
SELECT /*+ USE_MERGE(hle dates) */ ... FROM
) bar ON conditions
)
)
When I run the query from any remote db link on any other server, e.g. SELECT * from someschema.my_view#db_link, I get:
ORA-00928: missing SELECT keyword
ORA-02063: preceding line from PLLDB
00928. 00000 - "missing SELECT keyword"
*Cause:
*Action:
Error at Line: 2 Column: 9
Oracle thinks line 2 is a problem. Here are the first five actual lines:
WITH dates AS (
-- Get days
SELECT /*+ materialize */
row_number() OVER (ORDER BY begin_period DESC) rn,
'D' AS interval_type,
All other views work perfectly over the DB link (once edited to work around any related Oracle bugs).
Why does this view work perfectly locally but not over a db link?
Referring from Here
BUG 768478 The message "ORA-00928: missing SELECT keyword" can occur when Oracle cost-based optimization attempts to rewrite a query that contains a set operator (e.g. UNION, MINUS, or INTERSECT) with a materialized view.
There are three workarounds:
1. Disable query rewrite with an "ALTER {SESSION|SYSTEM} DISABLE QUERY REWRITE" statement.
2. Use a NOREWRITE hint with all SELECT statements referenced by the set operator.
3. Use a REWRITE(mv) hint with all SELECT statements in the set operator to tell the optimizer to explicitly use a materialized view.
Scalar expressions referencing SQL factoring elements ( WITH ... AS ) are not fully supported within view's subqueries. Acessing it locally work fine but remote access via dblinks errors out every time.

Why the count(*) in a sql prepare statement type is really small?

I found the "count() over()" will be much faster compare to the "select count() from table".
e.g
use count(*) over
with CTE as(
select col_A,col_B,totalNumber=count(*) over() from table1 where conditions..)
select totalNumber from CTE
use select count(*) from ( or use count(1) as well)
select count(*) from table1 where conditions..
In my local testing on SQL Server 2K5, the count() over* will be 4X faster if the search criteria is complex and the rows returned is large.
But why the count(**) over perform so faster?
Thanks in adv.
Vance
Update
I think really missed some details:
Actually I use "prepare statement" sql for my test like:
exec sp_executesql N'SELECT count(*)
FROM tableA WHERE (aaa in(#P0))
AND (bbb like #P1)',
N'#P0 nvarchar(4000),#P1 nvarchar(4000)',N'XXXXXXX-XXXX-XXX',N'%AAA%'
Execution Plan says "HashMatch" cost 61%, others is "index seek". And the execution time will be 1484ms and logical reads around 4000.
This is slow when compares to
SELECT count(*)
FROM tableA WHERE (aaa in('XXXXXXX-XXXX-XXX'))
AND (bbb like '%AAA%')
Execution plan says "clustered index seek" cost 98%. And the execution time is 46ms and logical reads will be 8000.
And if changes to the first sql to :
exec sp_executesql N'with CTE as(
SELECT total=count(*) over ()
FROM tableA WHERE (aaa in(#P0))
AND (bbb like #P1)) select top 1total from cte',
N'#P0 nvarchar(4000),#P1 nvarchar(4000)',N'XXXXXXX-XXXX-XXX',N'%AAA%'
Execution plan says "clustered index seek 58%', no "hashmatch join" occurs.
And the execution time is 15ms and logical reads is: 8404.
so, does "hash match join" has much overhead for the performance?

Resources