I've tried to insert a list in a database but I've got some the error: org.springframework.jdbc.BadSqlGrammarException: SqlSession operation; bad SQL grammar []; nested exception is java.sql.SQLException: ORA-00913: too many values (...).
The code that I've used:
<insert id="insertListMyObject" parameterType="java.util.List" >
INSERT INTO my_table
(ID_ITEM,
ATT1,
ATT2)
VALUES
<foreach collection="list" item="item" index="index" open="(" close=")" separator=",">
#{item.idItem, jdbcType=BIGINT},
#{item.att1, jdbcType=INTEGER},
#{item.att2, jdbcType=STRING}
</foreach>
</insert>
My dao cals the method:
SqlSessionTemplate().insert(MAPPER+".insertListMyObject", parameterList);
Where the parameterList is:
List<MyObjects>.
Does someone have a clue about what's this error? Or if does exists a better way to do multiples inserts operation.
Many thanks!
Set the separator as given below
separator="),("
by using following query you may insert multiple records at a time using Mybatis and Oracle.
<insert id="insertListMyObject" parameterType="map" >
BEGIN
insert into table_name values (11,11);
insert into table_name2 values (11,112);
END;
</insert>
this is how i did for oracle and it works. Note that parameterType=map is not necessary a map it can be anything according to your needs.
config log4j to mybatis ,you can find the bugs.
trying
<insert id="insertListMyObject" parameterType="java.util.List" >
INSERT INTO my_table
(ID_ITEM,
ATT1,
ATT2)
VALUES
<foreach collection="list" item="item" index="index" separator=",">
(#{item.idItem, jdbcType=BIGINT},
#{item.att1, jdbcType=INTEGER},
#{item.att2, jdbcType=STRING})
</foreach>
</insert>
I wonder if you can do this with an oracle INSERT statement. The INSERT with VALUES (other than the one with the subquery) does allow values for one row only!
To do so, try a batch insert. An MyBatis example can be found here.
something like this in your DAO layer might help
public class MyBatisDao
{
private SqlSessionFactory mSqlSessionFactory;
public void insertUsers(List<User> users) {
SqlSession session = mSqlSessionFactory.openSession(ExecutorType.BATCH);
try {
for(User user:users)
{
session.insert("com.you.insertUsers",user);
}
}catch(Exception e) {
} finally {
session.close();
}
}
}
I suggest you to use batch, it is much better, and it is standard. This query will not work on some databases (Oracle for example).
Related
I connected to database in my java program. I have a situation where I need to pass filter values dynamically, filter values depends of others parts of java code
Example query: select * from table1 where id in (dynamic and multiple)?
How to pass these dynamic and multiple values using Java connection.
Try this
String query = "select * from emp where id in(##)";
create the in clause like this
String inClause = "'abcd', 'cedf', '1234'";
String finalQuery = query.replace("##", inClause );
If you are using iBatis, you can try with below sql query:-
<select id="table1Result" resultMap="table1Map">
select * from table1 where id in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"</select>
While calling it from java, pass a List of ids.
I have a list of Integers which I want to (batch) insert into an SQL Server table with a single integer column.
The problem is that some of the values being inserted might already exist in the table. Is there a way of performing a batch "insert if missing" into Sql Server and MyBatis?
The following mapper worked for me :
<insert id="batchAddIntegers" parameterType="java.util.List">
DECLARE #ValuesToInsertTempTable TABLE (ColumnName integer)
DECLARE #UpdateVariable integer
SET NOCOUNT ON
INSERT INTO #ValuesToInsertTempTable (ColumnName) VALUES
<foreach item="item" index="index" collection="list" open="(" separator="),(" close=")">
#{item}
</foreach>
SET NOCOUNT OFF
MERGE TargetTable
USING #ValuesToInsertTempTable AS S
ON TargetTable.ColumnName=S.ColumnName
WHEN NOT MATCHED THEN
INSERT (ColumnName) VALUES (S.ColumnName)
WHEN MATCHED THEN
UPDATE SET #UpdateVariable = #UpdateVariable + 1;
</insert>
<insert id="insertIntoScheduleReportUserLink" parameterType="com.mypackage.model.ScheduleReport">
<selectKey keyProperty="id" resultType="java.lang.Integer" order="BEFORE">
select NEXTVAL('schedule_report_user_link_sequence')
</selectKey>
INSERT INTO schedule_report_user_link(
id, schedule_report_detail_id, to_user_id)
<foreach collection="selectedUsers" item="user" separator=",">
VALUES (#{id}, #{scheduleReportDetail.id}, #{user.id})
</foreach>;
</insert>
Here I am using for each loop to multiple insert. I need to know if selectKey generate new id for each insert?
Is there any better approach?
The loop is running only of the insert section not on the key generation part.
So its seems the key will be generated once.
Don't depend on hypothesis run for a little data and see it for your self.
I'm running into an issue where I'm trying to insert BATCH of roughly 10,000 records into an Oracle 11g table of 13 columns. Actually this is blocked if I try more than 1000 records. Also, fine grained tests for a BATCH insert of 500 records is too slow as well.
The BATCH is generating huge trace files on the database sever due to ORA-4031 errors. The SQL statement running in each session is over 80,000 lines long, taking as input over 42,000 bind variables.
Driver: oracle.jdbc.driver.OracleDriver
I'm trying to satisfy the requirement: If any data for an insert is invalid, I got to rollback.
My question is:
Is there a way to tell MyBatis to divide the incoming bulky batch into small batches say 10 records each, insert them but rollback all the batches if one of the batch fails and commit only when all the batches are sucessfully inserted?
Or is there an alternative approach to this?
Below is the xml mapping for the insert:
<insert id="insertToTable" parameterType="java.util.List">
INSERT ALL
<foreach item="line" collection="list" >
<foreach item="lineItem"
collection="line.entrySet()" open="" close="" separator="">
into
TABLE_TEST_T
(col1, col2, col3, col4, col5,
col6, col7, col8, col9, col10,
col11, col12, col13)
values(
<!-- #{lineItem.item1, jdbcType=DATE}, -->
#{lineItem.item1, jdbcType=VARCHAR},
#{lineItem.item2, jdbcType=VARCHAR},
#{lineItem.item3, jdbcType=VARCHAR},
#{lineItem.item4, jdbcType=NUMERIC},
#{lineItem.item5, jdbcType=NUMERIC},
#{lineItem.item6, jdbcType=NUMERIC},
#{lineItem.item7, jdbcType=NUMERIC},
#{lineItem.item8, jdbcType=NUMERIC},
#{lineItem.item9, jdbcType=NUMERIC},
#{lineItem.item10, jdbcType=NUMERIC},
#{lineItem.item11, jdbcType=NUMERIC},
#{lineItem.item12, jdbcType=NUMERIC},
#{lineItem.item13, jdbcType=NUMERIC}
)
</foreach>
</foreach>
SELECT * FROM dual
</insert>
Appreciate your feedback.
Yes, you can start a transaction and roll it back if error happens or commit it if there are no errors.
There are many ways to manage transactions in Java applications
Since you are using myBatis, you can look into SqlMapTransactionManager.
I used a camel EIP Splitter in a route and tied the query in a transaction. More details can be found at
http://camel.465427.n5.nabble.com/Camel-Mybatis-2-13-1-BATCH-of-10-000-records-tt5756211.html
I am trying to do an insert for return generated id INSERT RETURNING id. In postgres editor it work without problems, but in code execution - java 1.6 with iBatis 3 (8.4 postgres driver version 8.4-702) gives the error - Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near " RETURNING. "
It this means Postgres does not support Returning to insert?
I found this online - Concurrency issues when retriveing Ids of newly inserted rows with ibatis
but not how to do
Code iBatis xml
<insert id="insertNewItem" parameterType="itemAlias" useGeneratedKeys="true" keyProperty="item_id">
INSERT INTO items (
category_id,
description,
...)
VALUES(
#{category_id},
#{description},
...)
RETURNING item_id
</insert>
La respuesta es:
Public void insert(Item itemAlias) {
SqlSession session = sqlSessionFactory.openSession();
try {
Session.getMapper(ItemMapper.class).insert(itemAlias);
Logger.debug("itemAlias id:" + itemAlias.getItem_id()); // Here this you give you the generated key.
}
Finally {
Session.close();
}}
MyBatis xml
<insert id="insertNewItem" parameterType="itemAlias" useGeneratedKeys="true" keyProperty="item_id">
INSERT INTO items (
category_id,
description,
...)
VALUES(
#{category_id},
#{description},
...)
</insert>
MyBatis guys helped me. Thanks a lot
i htink u miss some concept here. RETURNING is neither RETURN nor SELECT. it just throw some variable out. To make it work, the statement gonna look like this
declare tmp integer;
INSERT INTO items (
category_id,
description,
...)
VALUES(
#{category_id},
#{description},
...)
RETURNING item_id INTO tmp
return tmp;
u can change integer to your primary key data type