I have a query along these lines, where I am trying to filter the result set by comparing tuples (like SQL multiple columns in IN clause):
select * from mytable where (key, value) in (values ('key1', 'value1'), ('key2', 'value2'), ... );
This is valid syntax and works fine on my PostgreSQL 9.3 database.
I want to invoke this query through Spring JDBC where the in
value pairs come from a List<Map<String, String>>
.
It would be nice to do something like this:
List<Map<String, String>> valuesMap = ...; String sql = "select * from mytable where (key, value) in (values :valuesMap)"; SqlParameterSource params = new MapSqlParameterSource("valuesMap", valuesMap); jdbcTemplate.query(sql, params, rowMapper);
When I try this, I get:
org.postgresql.util.PSQLException: No hstore extension installed. at org.postgresql.jdbc2.AbstractJdbc2Statement.setMap(AbstractJdbc2Statement.java:1707) ~[postgresql-9.3-1101-jdbc41.jar:na] at org.postgresql.jdbc2.AbstractJdbc2Statement.setObject(AbstractJdbc2Statement.java:1910) ~[postgresql-9.3-1101-jdbc41.jar:na] at org.postgresql.jdbc3g.AbstractJdbc3gStatement.setObject(AbstractJdbc3gStatement.java:36) ~[postgresql-9.3-1101-jdbc41.jar:na] at org.postgresql.jdbc4.AbstractJdbc4Statement.setObject(AbstractJdbc4Statement.java:47) ~[postgresql-9.3-1101-jdbc41.jar:na] at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:427) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:235) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:150) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.setValues(PreparedStatementCreatorFactory.java:287) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:244) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:623) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
I’ve looked at the the hstore extension it mentions. It doesn’t seem relevant to my problem.
Is there a way to accomplish this without dynamically building the SQL and parameter list?
Answer
All you have to do is to pass a list of arrays, where each array contains a key and value, like this:
HashMap<String , String > map = new HashMap<>(); map.put("key0", "value0"); map.put("key1", "value1"); Set<String> keys = map.keySet(); List<String[]> valuesMap = new ArrayList<>(); for(String key:keys){ String[] entry = {key,map.get(key)}; valuesMap.add(entry); } String sql = "select * from mytable where (key, value) in (values :valuesMap)"; SqlParameterSource params = new MapSqlParameterSource("valuesMap", valuesMap); jdbcTemplate.query(sql, params, rowMapper);
This is mentioned in the Spring documentation: http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/jdbc.html#jdbc-in-clause