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>
Related
I'm trying to make an insert all method inside my mapper.
The problem is with the the selectKey inside the foreach (it seems I cannot use it).
If I call, from the outside, a nextVal method it returns always the same number.
<select id="nextValKey" resultType="java.lang.Long">
SELECT MY_SEQUENCE.nextVal from dual
</select>
<insert id="insertAll" parameterType="list">
INSERT ALL
<foreach collection="items" item="item" index="i">
<![CDATA[
into MY_TABLE (ID)
values (
#{item.id, jdbcType=DECIMAL}
]]>
</foreach>
SELECT * FROM dual
</insert>
If I understand correctly you generate ids for items via call to nextValKey.
The problem is that mybatis used cached value if you invoke the same select statement for the second time in the same session.
If you have query that returns different values each time you can instruct mybatis to clear the cache after statement execution (by default this is off for select and is on for insert, update and delete):
<select id="nextValKey" resultType="java.lang.Long" flushCache="true">
SELECT MY_SEQUENCE.nextVal from dual
</select>
I don't know Java nor MyBatis.
However, why would you want to use INSERT ALL in this case? It is usually used when you want to insert rows into different tables, using the same INSERT statement.
In your case, though - as far as I understand it - all you do is (pseudocode)
insert into my_table (id) a_sequence_of_numbers
If that's so, and as that "sequence_of_numbers" gets its value from my_sequence, then just do it as
insert into my_table (id)
select my_sequence.nextval
from dual
connect by level <= 10; -- it would insert 10 numbers
[EDIT: how to insert bunch of values]
You'd do it as simple as that:
SQL> create table my_table (id number);
Table created.
SQL> set timing on
SQL>
SQL> insert into my_table
2 select level from dual
3 connect by level <= 10000;
10000 rows created.
Elapsed: 00:00:00.02
SQL>
Or, if you insist on a sequence you created,
SQL> insert into my_table
2 select seqa.nextval from dual
3 connect by level <= 10000;
10000 rows created.
Elapsed: 00:00:00.08
SQL>
I'm using the below insert query in mybatis. In ibatis, the same query returned seq_consumer_id.nextval to the calling method in java, and inserted the same into the consumer_id column. But in mybatis, return value of the method is always 1 (I'm assuming its the no of rows inserted), though consumer_id column is correctly updated from sequence. Can't we generate the key, insert it and return the same to java class in mybatis ?
<insert id="insertConsumer" parameterType="com.enrollment.vo.ConsumerVO">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select seq_consumer_id.nextval as id from dual
</selectKey>
insert into quotation_consumer (consumer_id, consumer_type, dob,
create_date, ENROLLMENT_INDICATOR, QUOTE_ID,IS_PRIMARY)
values(#{id},#{type.id}, #{birthdate, jdbcType=DATE}, default, #{enrollmentIndicator},
#{quoteId},#{isPrimary})
</insert>
Indeed the method returns the number of affected rows.
Sequence id is stored in ìd property of com.enrollment.vo.ConsumerVO passed as parameter.
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.
<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'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).