简体   繁体   中英

JDBC PreparedStatement in batch when columns to set vary from row to row

I am trying to batch updates using PreparedStatement where the data you get in varies in what you have available.

Simple example:

You have a table with column x and y. Your inputdata is a representation of rows where only the modified column is present. So for row 1 you have x='foo' and for row 2 you have y='bar'. In order to batch these with a PreparedStatement you need one SQL statement: "update table where x=?,y=? where etc".

The solution that I am working towards is setting the column where you dont have any value to the value that is already present, but I'm not sure if this is possible. In raw SQL you could write "update table where x=x and y='foo' where etc", however I haven't found any ways to achieve this by setting the "?" parameter to be a reference to the column, it seems it's not possible.

Is it possible to handle this case at all with PreparedStatements? I apologize if my explanation is poor.

Assuming the values you want to set are all non-null, you could use a statement like

update sometable set column1 = coalesce(?, column1), colum2 = coalesce(?, column2)

Then when the value should not be updated, use either PreparedStatement.setNull with an appropriate java.sql.Types value or a PreparedStatement.setXXX of the appropriate type with a null as value.

As discussed in the comments, an alternative if you do need to update to null , is to use a custom function with a sentinel value (either for updating to null or for using the current value). Something like:

update sometable set column1 = conditional_update(?, column1), colum2 = conditional_update(?, column2)

Where conditional_update would be something like (using Firebird 3 PSQL syntax):

create function conditional_update(new_value varchar(500), original_value varchar(500)) 
  returns varchar(500)
as
begin
  if (new_value = '$$NO_UPDATE$$') then
     return original_value;
  else
     return new_value;
end

Where using $$NO_UPDATE$$ is a sentinel value for not updating. A potential downside of this solution is the typing of columns as a string type. You always need to use string types (I'm not sure if there are databases that would supports dynamic parameters and return types in this situation).

Let me rephrase your problem and you please tell me if this is right: You want to be able to have the update process

  • sometimes you only update for a specific x
  • sometimes you only update for a specific y
  • sometimes you update for specific x and y combined

Correct? If 'yes' then the next issue is implementation possibilities.

You suggested trying to put the column itself into the parameter. Even if that's possible I'd still recommend against it. The code will get confusing.

I suggest you create a java method that builds and returns the query string (or at least the 'where' clause) based on your available parameters (x, y, etc) Your code for invoking the JDBC Prepared statement will invoke that method to get a query String. You will still benefit from using prepared statements. The cost is that your database will be caching several different statements instead of one, but I imagine that is a minimal issue.

You can think of auxiliar "?" variable for each column which will manage if the column should be updated or not.

update table
set x = case when 0 = ? then x else ? end,
    y = case when 0 = ? then y else ? end
where etc;

Passing 0 for each 0 =? will not update the column whereas passing 1 will update it to the value you specified.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM