I am trying to do two JdbcTemplate updates in same method, but only the first one executes. How can I do two update statements in one method? EduId and timeId returns correct values and I guess the SQL syntax is valid so the problem isn't there.
EDIT: I am using MySQL.
#Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.SERIALIZABLE, readOnly=false)
public void moveEdu(int eduId, int timeId) {
final String sql = "UPDATE timeslot ts"
+ " INNER JOIN eduevent ee ON ts.edu_id = ee.edu_id"
+ " SET ts.edu_id = null"
+ " WHERE ts.edu_id = ?;";
Object[] parameters = new Object[] {eduId};
final String sql2 = "UPDATE timeslot ts"
+ " INNER JOIN eduevent ee ON ts.edu_id = ee.edu_id"
+ " SET ts.edu_id = ?"
+ " WHERE ts.time_id = ?;";
Object[] parameters2 = new Object[] {eduId, timeId};
jdbcTemplate.update(sql, parameters);
jdbcTemplate.update(sql2, parameters2);
}
You code looks fine.
You can try to do all your updates in one
...
SET ts.edu_id=CASE
WHEN ts.time_id=? THEN ? <-- time_id=timeID then eduID
ELSE null
END
WHERE ts.time_id = ? OR ts.edu_id = ?
and params should be
Object[] parameters = new Object[] {timeId, eduId, timeId, eduId};
I solved the problem by removing "INNER JOIN" from that SQL2 string.
Related
I am creating the Spring Boot application with a PostgreSQL database. and I am using JDBCTemplate to perform DB operations. as per my requirement, I want a count of the row from CONTRACT_VIEW_2 table where the value of LICENSE_PLATE = "xxxxxx" and ZONE_CODE is IN ("x","y","z") but I am getting PSQL Exception.
I tried using MapSQLParameterSource but still, I facing the issue.
#Override
public Integer getAllZoneForLp(String lp,List<String> zones) {
MapSqlParameterSource zoneIds = new MapSqlParameterSource();
zoneIds.addValue("zoneIds",zones);
String sql = "select " +
"count(*) " +
"from contract_view_2 " +
"where license_plate = ? and zone_code IN (?)";
return jdbcTemplate.queryForObject(sql,Integer.class,lp,zoneIds);
}
I expect the row count in the result but I am getting PSQL Exception. I am attaching the image of the exception which I am getting.
Thanks in advance.
The problem with yours is you have added Namedparameter to JdbcTemplate.
So in case you are using NamedParameterJdbcTemplate
#Override
public Integer getAllZoneForLp(String lp,List<String> zones) {
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("lp", lp);
parameters.addValue("zoneIds",zones);
String sql = "select " +
"count(*) " +
"from contract_view_2 " +
"where license_plate = :lp and zone_code IN (:zoneIds)";
NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
return namedParameterJdbcTemplate.queryForObject(sql, parameters, Integer.class);
}
In case you want to use jdbcTemplate
#Override
public Integer getAllZoneForLp(String lp,List<String> zones) {
String sql = "select " +
"count(*) " +
"from contract_view_2 " +
"where license_plate = ? and zone_code IN (?)";
return jdbcTemplate.queryForObject(sql, Integer.class, new Object[] { lp, zones});
}
Go with NameParameterJdbcTemplate so that you won't miss any params.
Please change your query to
String sql = "select " +
"count(*) " +
"from contract_view_2 " +
"where license_plate = ? and zone_code IN (:zoneIds)";
Changes: changed ? to :zoneIds
Line zoneIds.addValue("zoneIds",zones); is using named parameter to bind it.
I am trying to change a normal query to Parameterized query using jdbcTemplate.queryForObject for avoiding SQL Injection. But the query returns EmptyResultDataAccessException - Incorrect result size: expected 1, actual 0 where the normal query works fine. Below is the normal query where i get the correct result.
StringBuilder builder = new StringBuilder();
String AcctNameBuilder = adhpDetailUtil.getAccName();
builder.append("select * " +
"from gfc.LSI_ELGBLTY " +
"where INSURANCE_ID = '" + request.getInsuranceId() + "' and " +
"SYS_CD = '" + request.getSystemId() + "' and " +
"ACCT_TYPE in (" + AcctNameBuilder.toString() + ")");
Here is the parameterized query that i have created from the above query.
StringBuilder builder = new StringBuilder();
String AcctNameBuilder = adhpDetailUtil.getAccName();
final String QUERY = "select * " + "from gfc.LSI_ELGBLTY " + "where INSURANCE_ID = ? and " + "SYS_CD = ? and " + "ACCT_TYPE in (?)";
Object[] params = new Object[] {
request.getInsuranceId(),request.getSystemId(),AcctNameBuilder};
String ids = jdbcTemplate.queryForObject(QUERY, params, String.class);
builder.append(ids)
In the first case, builder.append contains the exact query while in the second case jdbcTemplate.queryForObject is returning EmptyResultDataAccessException. What am I doing wrong here.
I don't believe you can just append ids for an "IN" clause like that.
The parameter for the "IN" clause is technically an Array. I ran into this a number of years ago and I don't think that this has ever been truly addressed.
If you think about it this is a fairly difficult problem as the query planner for preparing the statement cannot effectively bound the number of parameters.
I am developing an application that can update my database... However, I can't get my Java method working correctly. It gives me the following error: Must declare the scalar variable "#P0WHERE". Any suggestions?
The method I am using:
public void updateTable() throws SQLException
{
Scanner input = new Scanner(System.in);
System.out.println("Update the following:\n" + this);
this.getReservationInfo(input);
DataConnection connection = new DataConnection();
String query = "UPDATE " + TableName;
query += "Set Name = ?";
query += "WHERE Person_ID = " + id;
connection.updateData(query, person_name);
connection.closeConnection();
}
Add spaces before 'SET' and 'WHERE', otherwise it will not work.
String query = "UPDATE " + TableName;
query += " SET Name = ?";
query += " , Age = ?";
query += " , Col1 = ?"; //And other cols
query += " WHERE Person_ID = " + id;
EDIT: Changed query to update multiple columns.
I think so. You seem to be missing spaces. After the TableName and after the ?.
String query = "UPDATE " + TableName;
query += " Set Name = ?"; // tableSet not good, and
// ?WHERE is not valid add spaces.
query += " WHERE Person_ID = " + id;
I have a table in H2 DB
Order
--------
id (key)
MarketId1
MarketId2
MarketId3
ListName1
ListName2
ListName3
From XML I'm getting list of ListOrder
public final class ListOrder
{
public long listId;
public String Name;
}
So I have 3 prepared statements
"UPDATE Order set " + ListName1 + " = ? WHERE " + MarketId1 + " = ?"
"UPDATE Order set " + ListName2 + " = ? WHERE " + MarketId2 + " = ?"
"UPDATE Order set " + ListName3 + " = ? WHERE " + MarketId3 + " = ?"
The in a method I prepare a list of PreparedStament to execute
final PreparedStatement statement1 = connection.prepareStatement(QUERY1);
final PreparedStatement statement2 = connection.prepareStatement(QUERY2);
final PreparedStatement statement3 = connection.prepareStatement(QUERY3);
for (ListOrder listOrder: listOrders)
{
statement1.setString(1, listOrder.Name);
statement1.setLong(2, listOrder.listId);
statement1.addBatch();
statement2.setString(1, listOrder.Name);
statement2.setLong(2, listName.listId);
statement2.addBatch();
statement3.setString(1, listName.Name);
statement3.setLong(2, listOrder.listId);
statement3.addBatch();
}
return new ArrayList<PreparedStatement>(){{add(statement1); add(statement2); add(statement3);}};
I'm a SQL noob. Is there any better way of doing it? I assume that MarketId 1 2 3 could be the same. ListNames could be null (there will be at least one)
UPDATE:
In code I would write something like this (prob change to HashMap)
for (ListOrder listOrder: listOrders)
{
for(Order order : orders)
{
if(order.marketID1 == listOrder.listID)
order.listName1 = listOrder.Name; //break if no dups
if(order.marketID2 == listOrder.listID)
order.listName2 = listOrder.Name;
if(order.marketID3 == listOrder.listID)
order.listName3 = listOrder.Name;
}
}
You can use update comma separated
UPDATE <TABLE>
SET COL1 = <VAL1>,
COL2= <VAL2>
WHERE <CONDITION>
Is it this what you expect as one update query?
Unless you are trying to update the same record, then there is no way to do this easily or efficiently in a single query. Otherwise, assuming this is the desired result, you could use an OR (or an AND if that is desired) statement such as:
UPDATE Order
SET ListName1=?, ListName2=?, ListName3=?
WHERE MarketId1=? OR MarketId2=? OR MarketId3=?
You might also consider updating your table to use a one:many relationship which might make your queries easier. For example:
Order
--------
id (key)
name
etc
Market_List
--------
id (key)
order_id (fk)
market
listname
public static final String UPDATE_DOCUMENTS_WITH_TO_DELETE_FLAG_FOR_USER_SQL = "\n" +
"UPDATE document d \n" +
"SET d.indexed = :flagValue \n" +
"WHERE d.user_id = :userId \n" +
"AND d.to_delete = :toDelete";
public static final String UPDATE_DOCUMENTS_WITH_TO_DELETE_FLAG_FOR_USER_WITH_EXCEPTIONS_SQL = "\n" +
"UPDATE document d \n" +
"SET d.indexed = :flagValue \n" +
"WHERE d.user_id = :userId \n" +
"AND d.to_delete = :toDelete \n" +
"AND d.id NOT IN (:exceptForDocuments)";
public int markUserDocumentsToDeleteAsUnindexed(String userId,Collection<String> exceptForDocuments) {
Map<String,Object> params = Maps.newHashMap();
params.put("flagValue",false);
params.put("userId",userId);
params.put("toDelete",1);
params.put("exceptForDocuments",exceptForDocuments);
if ( exceptForDocuments.isEmpty() ) {
return jdbcTemplate.update(UPDATE_DOCUMENTS_WITH_TO_DELETE_FLAG_FOR_USER_SQL, params);
}
else {
return jdbcTemplate.update(UPDATE_DOCUMENTS_WITH_TO_DELETE_FLAG_FOR_USER_WITH_EXCEPTIONS_SQL,params);
}
}
Is there a way to use a single query to perform both updates?
Because actually using the UPDATE_DOCUMENTS_WITH_TO_DELETE_FLAG_FOR_USER_WITH_EXCEPTIONS_SQL query seems to work against H2, but not MySQL.
Any idea to avoid this query duplication?
The problem is likely because not every driver can handle parameterized arrays/collections. If you have complete control over the exceptForDocuments contents, you can serialize it to SQL yourself (with simple sanitization checks) and then conditionally append it without using parameters.