Is there any possibility to specify the sequence generator as a value for a column in SimpleJdbcInsert, JdbcTemplate, NamedParameterJdbcTemplate or any other class for batch execution?
e.g., I want to achieve the SQL to be generated by any of the above classes as:
INSERT INTO SOME_TABLE_NAME (ID, COLUMN_A,...) VALUES (SOME_SEQUENCE.NEXTVAL, 'value for column A', ...);
A sample code snippet is like:
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
List<SomeTableEntity> listOfEntities; // received from method parameter
SimpleJdbcInsert sql = new SimpleJdbcInsert(dataSource).withTableName("SOME_TABLE_NAME");
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(listOfEntities.toArray());
sql.executeBatch(batch);
I tried to trick the SimpleJdbcInsert as:
SqlParameterSource id = new MapSqlParameterSource("ID", "SOME_SEQUENCE.nextval"));
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(listOfEntities.toArray());
List<SqlParameterSource> params = new ArrayList<>(batch.length + 1);
params.add(id);
for (SqlParameterSource param : batch)
{
params.add(param);
}
sql.executeBatch(params.toArray(new SqlParameterSource[] {}));
But not to a surprise, that didn't worked since the ID column is of type numeric and it tried to fill the value as "SOME_SEQUENCE.nextval" instead of evaluating the result of SOME_SEQUENCE.nextval.
PS: There are too many columns in the table and due to that I do not want to use a prepared statement solution
String sql = "INSERT INTO USER
(USER_PK, ACCOUNTNUMBER, FIRSTNAME, LASTNAME, EMAIL )
VALUES
(user.nextval, ?, ?, ?, ?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, accountNumber);
ps.setString(2, firstName);
ps.setString(3, lastName);
ps.setString(4, email);
Related
I am using jdbcTemplate to write data to my Oracle DB. I would like to reuse my code for the same table but in two different enviroments and the difference between these two enviroments is only one column missing. So before writing the data I need to check if the column is there or not to use the correct sql query, other I will get an exception. So I would like to have something like:
if(column3IsMissing){
String sql = String.format("insert into %s %s", MYTABLE,
"(column1, column2) values (?, ?)");
}else{
String sql = String.format("insert into %s %s", MYTABLE,
"(column1, column2, column3) values (?, ?, ?)");
}
jdbcTemplate.batchUpdate(sql, data, types);
Can anyone give me hint how should I implement the column3IsMissing check here? Thank you very much in advanced!
Oracle offer three different views to get table columns information: ALL_TAB_COLUMNS, USER_TAB_COLUMNS and DBA_TAB_COLUMNS.
You can run query like below with JDBC, to confirm if column exists before running your insert query.
select column_name from ALL_TAB_COLUMNS where TABLE_NAME = 'MYTABLE';
In order to get check the columns size. put all your column into array and check if
columnSize = 2.
String[] columnList = {column1,column2,column3);
if(columnList.size()==2){
String sql = String.format("insert into %s %s", MYTABLE,
"(column1, column2) values (?, ?)");
}else{
String sql = String.format("insert into %s %s", MYTABLE,
"(column1, column2, column3) values (?, ?, ?)");
}
jdbcTemplate.batchUpdate(sql, data, types);
I have an EMPLOYEE table that has 4 fields; ID, NAME, AGE, SALARY. ID is unique and auto-increment.
Below is the code to insert a row in the table, using Spring's JDBCTemplate. Please suggest, how can I auto increment ID field.
String sql = "insert into employee values (?,?,?,?)"
jdbcTemplate.update( sql, ID, bean.getName(), bean.getAge(), bean.getSalary())
I see, you tag your question Oracle, use Oracle sequence then.
String sql = "insert into Employee values (id_seq.nextval, ?, ?, ?)";
jdbcTemplate.update(sql, bean.getName(), bean.getAge(), bean.getSalary());
Ref: How to create Sequence in Oracle.
Just add following code to your domain:
Ref: http://docs.spring.io/spring/docs/2.5.x/reference/jdbc.html#jdbc-auto-genereted-keys
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
final String INSERT_SQL = "insert into my_test (name) values(?)";
final String name = "Rob";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(
new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement ps =
connection.prepareStatement(INSERT_SQL, new String[] {"id"});
ps.setString(1, name);
return ps;
}
},
keyHolder);
I want to make use of spring JdbcTemplate to insert a line and return the id autogenerated by the mysql db.
Without spring I'd do similar as follows:
String sql = "INSERT INTO mytable (id, filename, timestamp) VALUES (NULL, ?, NOW())";
Statement st = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
st.setString("test.csv");
st.executeUpdate();
st.getGeneratedKeys().next().getLong(1);
Question: how could I achive the same with JdbcTemplate?
In short its
Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(
parameters));
You can check my answer in identity from sql insert via jdbctemplate
I'm using a UI that I've built to get input and MySQL to store the data locally. However, when I use the MySQL insert function, I'm encountering the following error:
java.sql.SQLException: No value specified for parameter 5
I only have four input fields, and four columns in the table; however, my debugger says I have seven value parameters. Here is the Insert statement:
private static final String GLInsert = "INSERT INTO gl_maint(GL_MAINT_NUM, GL_MAINT_NAME, GL_TYPE, BAL_FORWARD)"
+ "VALUES(?, ?, ?, ?) ON DUPLICATE KEY UPDATE "
+ "GL_MAINT_NAME = ?, GL_MAINT_TYPE = ?, BAL_FORWARD = ?";
And the preparedStatement method:
public void InsertGL(String ANstr, String ANAstr, String AIstr, double balfor) {
try {
conn = DriverManager.getConnection(ConnCheck, user, password);
GL_List = FXCollections.observableArrayList();
st = conn.prepareStatement(GLInsert);
st.setString(1, ANstr);
st.setString(2, ANAstr);
st.setString(3, AIstr);
st.setDouble(4, balfor);
st.executeUpdate();
conn.close();
} catch (SQLException ex) {
Logger.getLogger(GLMaintAcct.class.getName()).log(Level.SEVERE, null, ex);
}
}
The issue is you have 7 parameters according to this query:
"INSERT INTO gl_maint(GL_MAINT_NUM, GL_MAINT_NAME, GL_TYPE, BAL_FORWARD)"
+ "VALUES(?, ?, ?, ?) ON DUPLICATE KEY UPDATE "
+ "GL_MAINT_NAME = ?, GL_MAINT_TYPE = ?, BAL_FORWARD = ?";
But you have just 4 value assigned like below:
st.setString(1, ANstr);
st.setString(2, ANAstr);
st.setString(3, AIstr);
st.setDouble(4, balfor);
You should add other 3 values like this providing their types:
st.setString(5, value5);
st.setDouble(6, value6);
st.setString(7, value7);
I have my below method which accepts two parameters-
userId and attributes Map
attributes Map will have column names and column values-
Let's take an example if I have 5 columns in the above map, then there will be 5 keys and 5 values as well.
so then my SQL will look like this-
String sql = "INSERT INTO PROFILE(userId, colA, colB, colC, colD, colE) VALUES ( ?, ?, ?, ?, ?, ?) ";
In the same way, my query statement will look like-
BoundStatement query = prBatchInsert.bind(userId, colAValue, colBValue, colCValue, colDValue, colEValue);
But in some case it might be possible that the attributes map will have 20 columns. So basis on that, I need to make sql and query statement.
Below is the code which almost assume that table will have four columns only which is not right.
public void upsertAttributes(final String userId, final Map<String, String> attributes) {
try {
String[] keys = (String[])attributes.keySet().toArray();
String sql = "INSERT INTO PROFILE(userId, "+keys[0]+", "+keys[1]+", "+keys[2]+", "+keys[3]+") VALUES ( ?, ?, ?, ?, ?) ";
BoundStatement query = prBatchInsert.bind(userId, attributes.get(keys[0]), attributes.get(keys[1]), attributes.get(keys[2]), attributes.get(keys[3]));
} catch (Exception e) {
LOG.error(e);
}
}
How can i write the above method more generic corresponding to the attributes Map?
You should use Spring jdbctemplate, it has loads of apis for this. Check out this link : http://static.springsource.org/spring/docs/2.0.8/api/org/springframework/jdbc/core/JdbcTemplate.html
EDIT:
Check this link : http://www.mkyong.com/spring/spring-named-parameters-examples-in-simplejdbctemplate/
It exactly does what you want.
EDIT: If you dont want to use Spring then in order to achieve this you need to generate complete sql string dynamically. Binding will not be used.
See this code[I have not run this code, but this is the basic idea to achieve this]:
public void upsertAttributes(final String userId, final Map<String, String> attributes) {
try {
String[] keys = (String[])attributes.keySet().toArray();
String sql = "INSERT INTO PROFILE(userId, "+keys[0]+", "+keys[1]+", "+keys[2]+", "+keys[3]+") VALUES ( ?, ?, ?, ?, ?) ";
StringBuffer keysStmt = new StringBuffer("INSERT INTO PROFILE("+userId);
StringBuffer valuesStmt = new StringBuffer(" VALUES (" );
Iterator itr = attributes.keySet().iterator();
while(itr.hasNext()){
String key = itr.next();
keysStmt.append(","+key);
valuesStmt.append(attributes.get(key)+",");
}
//remove last comma
valuesStmt = new StringBuffer(valuesStmt.toString().substring(0,valuesStmt.length-1));
sql = keysStmt.append(")")+valuesStmt.append(")");
} catch (Exception e) {
LOG.error(e);
}
}