Issue returning id with Postgres 8.4 - java

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

Related

H2 Insert via stored procedure

I'm trying to write an H2 stored procedure to insert some values into a table. I'm doing this because in my unit testing environment, I'd rather connect to an in-memory than a real database. Here's what I have (note that I'm doing this in groovy, not java, but I don't think that matters).
Sql sql = new Sql(JdbcConnectionPool.create("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "user", "password"))
sql.executeUpdate("CREATE TABLE data (key VARCHAR(255) PRIMARY KEY,value VARCHAR(1023) )")
sql.execute("CREATE ALIAS insertInto FOR \"com.vanguard.fig.batch.core.StoredProcs.insertInto\"")
sql.execute("CALL insertInto(?,?)", val1, val2)
sql.eachRow("Select * From data") { row ->
println row
}
And my procedure is as follows
public class StoredProcs {
void insertInto(java.sql.Connection con, String val1, String val2) throws Exception {
String resultValue=null;
Sql sql = new Sql(con)
sql.executeInsert("Insert Into data VALUES(?, ?)", val1, val2)
}
}
The examples were all fairly confusing and I'm not sure I'm doing this right. Here's the error
WARNING: Failed to execute: CALL insertInto(?,?) because: Parameter "#1" is not set; SQL statement:
Insert Into data VALUES(?, ?) [90012-193]
Which version of h2 are you using.?
Looks like h2 has a bug filed for this issue. GitHub Bug
Please upgrade it to the latest version to fix this issue.
PS : I was not able to add this as comment since i need to have 50 reputation to add a comment. Hope this helps

I'm having an issue with what would seem to be a simple insert using MyBatis/java.

I'm having an issue with what would seem to be a simple insert using myBatis and java.
The exception is:
org.apache.ibatis.executor.ExecutorException:
Error preparing statement. Cause:
java.lang.ArrayIndexOutOfBoundsException:
Array index out of range: 12
The query in my mapper is as follows:
<insert id="insertRuleResult"
useGeneratedKeys="true"
keyProperty="ruleResult.recordDetailId"
keyColumn="RECORD_DETAIL_ID">
INSERT INTO KMV_DBO.RULE_RESULT(
RECORD_ID,
RECORD_DETAIL_ID,
SUBJECT_AREA_ID,
RULE_NAME,
RULE_RESULT,
MESSAGE,
COLUMN_NAME,
ORIGINAL_VALUE,
NEW_VALUE,
STATUS,
SOURCE,
USER_NOTE,
CREATED_DATE,
BATCH_STATUS,
UPDATED_BY,
UPDATED_DATE
)
VALUES (
KMV_DBO.RULE_IMPACTED_DETAIL_SEQ.NEXTVAL,
#{ruleResult.subjectAreaId,jdbcType=VARCHAR},
#{ruleResult.ruleName,jdbcType=VARCHAR},
#{ruleResult.ruleResult,jdbcType=VARCHAR},
#{ruleResult.message,jdbcType=VARCHAR},
#{ruleResult.columnName,jdbcType=VARCHAR},
#{ruleResult.originalValue,jdbcType=VARCHAR},
#{ruleResult.newValue,jdbcType=VARCHAR},
#{ruleResult.recordId,jdbcType=NUMERIC},
#{ruleResult.status,jdbcType=VARCHAR},
#{ruleResult.source,jdbcType=VARCHAR},
#{ruleResult.userNote,jdbcType=VARCHAR},
SYSDATE,
'Open',
#{user.nwieId,jdbcType=VARCHAR},
NULL
)
</insert>
I tried the following variation, but it also doesn't work if I'm not using the schema owner id to connect. The error was sequence not found:
<insert id="insertRuleResult">
<selectKey keyProperty="ruleResult.recordDetailId" keyColumn="RECORD_DETAIL_ID" resultType="int" order="BEFORE">
SELECT RULE_IMPACTED_DETAIL_SEQ.NEXTVAL FROM DUAL
</selectKey>
INSERT INTO KMV_DBO.RULE_RESULT(
RECORD_ID,
RECORD_DETAIL_ID,
SUBJECT_AREA_ID,
RULE_NAME,
RULE_RESULT,
MESSAGE,
COLUMN_NAME,
ORIGINAL_VALUE,
NEW_VALUE,
STATUS,
SOURCE,
USER_NOTE,
CREATED_DATE,
BATCH_STATUS,
UPDATED_BY,
UPDATED_DATE
) VALUES (
#{ruleResult.recordId,jdbcType=NUMERIC},
#{ruleResult.recordDetailId,jdbcType=NUMERIC},
#{ruleResult.subjectAreaId,jdbcType=VARCHAR},
#{ruleResult.ruleName,jdbcType=VARCHAR},
#{ruleResult.ruleResult,jdbcType=VARCHAR},
#{ruleResult.message,jdbcType=VARCHAR},
#{ruleResult.columnName,jdbcType=VARCHAR},
#{ruleResult.originalValue,jdbcType=VARCHAR},
#{ruleResult.newValue,jdbcType=VARCHAR},
#{ruleResult.status,jdbcType=VARCHAR},
#{ruleResult.source,jdbcType=VARCHAR},
#{ruleResult.userNote,jdbcType=VARCHAR},
SYSDATE,
'Open',
#{user.nwieId,jdbcType=VARCHAR},
NULL
)
</insert>
The values being inserted are basic strings and numbers.
Thanks for any advice!
org.apache.ibatis.executor.ExecutorException:
Error preparing statement. Cause:
java.lang.ArrayIndexOutOfBoundsException:
Array index out of range: 12
It means it fails at 13th (because internal array is zero-based) value which is SYSDATE.
I would advise, try to insert hard coded values first to see if it works then pass dynamic value.

Get the id of last inserted record in mybatis

I am newbie to mybatis. I am trying to get the id of last inserted record. My database is mysql and my mapper xml is
<insert id="insertSelective" parameterType="com.mycom.myproject.db.mybatis.model.FileAttachment" >
<selectKey resultType="java.lang.Long" keyProperty="id" order="AFTER" >
SELECT LAST_INSERT_ID() as id
</selectKey>
insert into fileAttachment
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="name != null" >
name,
</if>
<if test="attachmentFileSize != null" >
size,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="name != null" >
#{name,jdbcType=VARCHAR},
</if>
<if test="attachmentFileSize != null" >
#{attachmentFileSize,jdbcType=INTEGER},
</if>
</trim>
</insert>
I thought statement written here 'SELECT LAST_INSERT_ID() as id' should return id of last inserted record but I am getting always 1 after inserting the record.
My mapper.java class I have method
int insertSelective(FileAttachment record);
In my dao class I am using
int id = fileAttachmentMapper.insertSelective(fileAttachment);
I am getting value of Id always 1 when new record is inserted. my Id field is auto incremented and records are inserting properly.
The id is injected in the object:
int num_of_record_inserted = fileAttachmentMapper.insertSelective(fileAttachment);
int id = fileAttachment.getId();
What selectKey does is to set the id in the object you are inserting, in this case in fileAttachment in its property id and AFTER record is inserted.
You only need to use
<insert id="insert" parameterType="com.mycom.myproject.db.mybatis.model.FileAttachment" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
There is no need of executing select query inside insert tag in MyBatis. It provides you new parameter for insert operation.Here define useGeneratedKeys="true", keyProperty="id", keyColumn="id".You can retrive value for id in following way
FileAttachment fileAttachment=fileAttachmentMapper.insertSelective(fileAttachment);
Integer id=fileAttachment.getId();
fileAttachment.getId() is used because in insert tag keyColumn="id" is define and you will get all return values inside fileAttachment reference of FileAttachment.
In fact, MyBatis has already provided this feature.You can use the option : "useGeneratedKeys" to get the last insert id.
Here is the explanation from MyBatis.(If you want to know more detailed info, you can go to MyBatis official page).
useGeneratedKeys (insert and update only) This tells MyBatis to use the JDBC getGeneratedKeys method to retrieve keys generated internally by the database (e.g. auto increment fields in RDBMS like MySQL or SQL Server). Default: false
If you are using xml:
<insert id="" parameterType="" useGeneratedKeys="true">
If you are using annotation:
#Insert("your sql goes here")
#Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int insert(FileAttachment fileAttachment) throws Exception;
Once you finish insert operation, the fileAttachment's setId() method will be invoked, and is set to id of last inserted record. You can use fileAttachment's getId() to get the last insert id.
I do hope this will help you.
I think the 1 that is being returned refers to the number of records that is updated/inserted. I think the id is set on the fileAttachment parameter that you passed to the call to insertSelective.
I hope in the writer, you can have a custom composite writer and there you can get the inserted ids.
(1) Adding on to Ruju's answer, in the insert statement you need to define attribute useGeneratedKeys=true, parameterType="object", keyProperty="objectId" and keyColumn="objectId" should be set with same primary key column name (objectId) from the table that stores the object record. The primary key column (objectId) should be set to AUTO_INCREMENT in the database table.
(2) When the insert statement is triggered the new generated primary key (objectId) will be stored in object, and u can retrieve it by accessing objectId property through using this methods (object.getObjectId() or object.objectId). Now this should give the exact and new generated primary. It worked for me....
Configuration need with codeGenerator :
<table schema="catalogue" tableName="my_table" >
<generatedKey column="my_table_id" sqlStatement="JDBC" identity="true" />
<columnOverride column="my_table_id" isGeneratedAlways="true"/>
</table>
http://www.mybatis.org/generator/configreference/generatedKey.html
after code generation the insert include auto update for the id field
After struggling alot, I got the following solution:
Use Case: if you are using sequence for generating primary key. and you want the id inserted to db
in xml:
<insert id="createEmployee"
parameterType="com.test.EmployeeModel">
<selectKey keyProperty="employeeId" keyColumn="EMPLOYEE_ID"
resultType="Long" order="BEFORE">
select EMPLOYEE_SEQ.NEXTVAL FROM DUAL
</selectKey>
INSERT INTO EMPLOYEE(EMPLOYEE_ID,EMPLOYEE_NAME)
VALUES
(#{employeeId,jdbcType=NUMERIC},#{EMPLOYEE_NAME,jdbcType=VARCHAR})
</insert>
in java side:
interface
public void createEmployee(EmployeeModel request);
in dao
getMapper().createEmployee(model);
getClient().commit();
Long employeeId= model.getEmployeeId();
System.out.println("Recent Employee Id: "+employeeId)

Which one to use - executeUpate or list - to insert and update and select?

I've written a stored procedure with the following sql statements
insert a row in table a
update a row in table b
insert a row in error table
select query to list the number of records in the error table
Can i use query.list() ? Will it does all the inserts, updates and returns the list properly?
I think we cannot use query.executeUpdate() as it returns only number of rows updated or inserted at last sql statement.
Thanks in advance,
Kathir
If it is stored procedure you can use do like this
try
{
con = connectionPool.getConnection();
proc = con.prepareCall("{ call set_death_age(?, ?) }");
proc.setString(1, dyingBard.getName());
proc.setInt(2, age);
proc.execute();
}
catch (SQLException e) {}
http://www.mkyong.com/hibernate/how-to-call-store-procedure-in-hibernate/
See above link for sample of how to call stored procedures with hibernate
if you are using spring, you can call stored procedures via Spring JdbcTemplate as well.

Db2 merge from jdbc with dynamic values

I would like to use the db2 merge statement submitting it as a statement from jdbc.
I am in the following scenario. I'm working with a proprietary persistence layer and I'm handling an entity I don't know whether it's already persisted or not and I would like to use the merge statement in order to insert or update a row on the database.
Is it possible?
Suppose I'm working with the table people with three columns: id, name, surname and I'm handling an entity with id="5", name="chuck", surname="norris" Am I able to issue:
MERGE INTO people AS t
USING (select '5' as id, 'chuck' as name, 'norris' as surname from SYSIBM.SYSDUMMY1)As s
ON (t.id = s.id)
WHEN MATCHED THEN
UPDATE SET t.name=s.name, t.surmane=s.surname
WHEN NOT MATCHED THEN
INSERT
(id, name, surname)
VALUES (s.id, s.name, s.surname)
such a statement? I'm trying to do that but I got an error. I don't think it's allowed to use a select after USING:
USING (select '5' as id, 'chuck' as name, 'norris' as surname from SYSIBM.SYSDUMMY1)As s
I also tryed to do:
USING VALUES('5','chuck','norris') AS s(id,chuck,norris)
but it dosn't work. Any help would be appreciated.
Besides, does anybody know if it's possible to use such a statement in a prepared statement, replacing the real values expressed into the USING part with '?' placeholders in order to set them to the prepared statement using the setXXX() methods?
Thanks
Thanks
Fil
The syntax for MERGE for your data would be something like this, assuming you're using DB2 Linux/Unix/Windows (LUW). The VALUES clause goes inside the parenthesis for the USING part.
Also, if you are using LUW, you cannot dynamically prepare a MERGE (I.E., your query can't have parameter markers) in LUW 9.5 or less. This was added in LUW 9.7.
MERGE INTO people AS t USING (
VALUES (5, 'Chuck', 'Norris'),
(6, 'John', 'Smith'),
(7, 'Abraham', 'Lincoln')
-- maybe more rows
) AS s (id, name, surname)
ON t.id = s.id
WHEN MATCHED THEN
UPDATE SET t.name=s.name, t.surname=s.surname
WHEN NOT MATCHED THEN
INSERT (id, name, surname)
VALUES (s.id, s.name, s.surname)
However, your actual problem with the fullselect may be that you have some typos in your query... for example "surmane" in UPDATE SET t.name=s.name, t.surmane=s.surname

Categories