Reputation: 605
I am using spring JDBCTemplate.
I have a scenario, where the parameters that need to be passed into my query function, are conditional/optional. For example, I have the following code:
List<RealTimeDTO> result = jdbcTemplate.query(sql, new Object[] {custId,
number, requestType, startDate, endDate}, new CCCRowMapper());
In the code, I passed in custId, number, requestType, etc.
However, requestType
is an optional parameter that may come back as null
or empty
so I don't want it to be passed into the Object[]
if it is either null
or empty
.
What can I do to handle this type of situation?
I could introduce logic where I only pass in the parameters I want into the Object[]
, however, I was wondering if there is an already built in functionality that handles this instead of me reinventing the wheel.
Upvotes: 8
Views: 22228
Reputation: 9415
To improve an existing answer, Keep a static query with only bind parameters. Don't 'build' a sql to avoid the pitfall of caching issues and sql injection.
List<RealTimeDTO> query(String name, String phone, int age) {
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
String sql = "SELECT foo, bar FROM FooBar" +
" WHERE (:name IS NULL OR name = :name)" +
" AND (:phone IS NULL OR phone = :phone)" +
" AND (:age = 0 OR age = :age)";
params.put("name", name);
params.put("phone", phone);
params.put("age", age);
return jdbcTemplate.query(sql, params, new CCCRowMapper());
}
Upvotes: 0
Reputation: 8841
I'd like to add NamedParameter to @Snozzlebert' answer with the next example.
You have to specify the parameters' type if you want to pass null values otherwise you will get a NullPointerException.
@Autowired
NamedParameterJdbcTemplate namedJdbcTemplate;
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("name", name, Types.VARCHAR);
parameters.addValue("phone", null, Types.VARCHAR);
parameters.addValue("age", null, Types.SMALLINT);
List<RealTimeDTO> list = namedJdbcTemplate.query(
"SELECT foo, bar\n" +
" FROM FooBar\n" +
" WHERE (:name IS NULL OR name = :name) AND \n" +
" (:phone IS NULL OR phone = :phone) AND \n" +
" (:age IS NULL OR age = :age)" +,
parameters,
new RealTimeDTOMapper());
Upvotes: 1
Reputation: 525
You can use a static SQL by checking the condition like ? IS NULL OR name = ?
. But you have to pass the argument twice AND pass the argument type (at.sql.Types
) twice.
String sql = "SELECT foo, bar" +
" FROM FooBar" +
" WHERE (? IS NULL OR name = ?) ";
jdbcTemplate.query(sql, new Object[]{name, name}, new int[]{Types.VARCHAR, Types.VARCHAR}, new CCCRowMapper());
IMO not really better than using conditions.
Upvotes: 1
Reputation: 159096
One option is to use NamedParameterJdbcTemplate
, so the parameter "list" (now a Map
) doesn't need to be modified, only the SQL does:
List<RealTimeDTO> query(String name) {
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
String sql = "SELECT foo, bar" +
" FROM FooBar" +
" WHERE name" + (name == null ? " IS NULL" : "= :name");
Map<String, Object> params = new HashMap<>();
params.put("name", name);
return jdbcTemplate.query(sql, params, new CCCRowMapper());
}
UPDATE
If you have many conditions that may need to be skipped, and all conditions might be eliminated, then use a StringJoiner
to build the WHERE
clause:
List<RealTimeDTO> query(String name, String phone, int age) {
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
StringJoiner where = new StringJoiner(" AND ", " WHERE ", "").setEmptyValue("");
if (name != null)
where.add("name = :name");
if (phone != null)
where.add("phone = :phone");
if (age != 0)
where.add("age = :age");
String sql = "SELECT foo, bar" +
" FROM FooBar" +
where;
Map<String, Object> params = new HashMap<>();
params.put("name", name);
params.put("phone", phone);
params.put("age", age);
return jdbcTemplate.query(sql, params, new CCCRowMapper());
}
Upvotes: 19