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?
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
Unfortunately, there isn't any easy way to bind a nested collection bind variable to PostgreSQL. You could generate the following SQL string instead
SELECT *
FROM mytable
WHERE (key, value) IN (
(?, ?),
(?, ?),
...
);
That's a bit of work to keep the SQL string and the variable bindings in sync.
You could, however, encode the map as JSON as such:
SELECT *
FROM mytable
WHERE (key, value) IN (
SELECT
t->>'key',
t->>'value'
FROM json_array_elements(?) AS t(v)
)
E.g.
SELECT *
FROM mytable
WHERE (key, value) IN (
SELECT
t->>'key',
t->>'value'
FROM json_array_elements(
'[{"key":"key1","value":"value1"},
{"key":"key2","value":"value2"}]'
) AS t(v)
)
In that case, you would only ever need a single VARCHAR bind variable
If you can't get your solution to work, you could also just concatenate the key and value.
Perhaps JDBC has less problems with this more basic syntax:
select *
from mytable
where (key||value) in (
('key1value1'),
('key2value2'),
...
);
For this to work, you'd need to first convert your Java Map to a List with the key and values concatenated as well.
It might not be an issue with the query, it might be that you don't have any hstore created/installed.
I suggest the following steps to debug your problem:
Try a very simple query, without any parameters.
If you get the same issue, check how to create extensions: http://www.postgresql.org/docs/9.1/static/sql-createextension.html
Otherwise, if the query executed correctly, try to use a simple parameter (with =?)
Finally, try named queries. Something like:
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(namedSql);
List<Integer> parameters = new ArrayList<Integer>();
for (A a : paramBeans)
parameters.add(a.getId());
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("placeholder1, parameters);
// create SQL with ?'s
String sql = NamedParameterUtils.substituteNamedParameters(parsedSql, parameterSource);
return sql;
Also check this discussion, I find it useful: How to execute IN() SQL queries with Spring's JDBCTemplate effectivly?
I need to write a code to read the values from a csv or delimited text file and save the corresponding values in a DB table.I am able to do this for csv files easily using the CSVReader utility.
But I am not able to decide how to approach the delimited case.
This is a part of my sample delimited file:
counterparty_id|counterparty_name|counterparty_type|counterparty_company_number
1|Jefferies||
2|ABNAMRO|ABNAMRO|234567
3|Wells Fargo|Wells Fargo|345678
This is the corresponding part of the table in postgres DB,public schema:
CREATE TABLE public.CARDS_COUNTERPARTY (
counterparty_id VARCHAR(255) NOT NULL ,
counterparty_name VARCHAR(255) NOT NULL ,
counterparty_type VARCHAR(255) ,
counterparty_company_number VARCHAR(255) ,
CONSTRAINT PK_CARDS_COUNTERPARTY PRIMARY KEY (counterparty_id)
) ;
My JAVA code should be able to read the values from the file and save or update in the DB table.Below is a snippet from the code that I used for the CSV file:
..
CsvReader counterparties = new CsvReader(filename);
counterparties.readHeaders();
Class.forName("org.postgresql.Driver");
Connection con = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", "postgres", "root");
Statement st = con.createStatement();
String query;
while(counterparties.readRecord())
{
String counterpartyId = counterparties.get("counterparty_id");
String counterpartyName = counterparties.get("counterparty_name");
String counterpartyType=counterparties.get("counterparty_type");
String counterpartyCompanyNumber = counterparties.get("counterparty_company_number");
..
query = "insert into public.cards_counterparty values (";
query = (new StringBuilder()).append(query).append(counterpartyId).append(", '").toString();
query = (new StringBuilder()).append(query).append(counterpartyName).append("', '").toString();
query = (new StringBuilder()).append(query).append(counterpartyType).append("', '").toString();
query = (new StringBuilder()).append(query).append(counterpartyCompanyNumber).append("', '").toString();
..
out.println((new StringBuilder()).append("Query : ").append(query).toString());
st.executeUpdate(query);
}
out.println("Data inserted...");
counterparties.close();
..
Can someone please tell me how I can read and update the values from the delimited file also in a generic way like the above.I do not want the values to be read to be dependent on the order of the headers in the file.
I'd use openCSV much easier than faffing about with a BufferedReader!
http://opencsv.sourceforge.net/
You can use a simple BufferedReader to read in the file line by line, you can then split each line into a string array using String.split("|"). This can then be assigned to any field you wish, or put into your SQL DB.
I have query like
`Select * from Table1 where xyz in (List of String to be Supplied).
In my java code. I have a dao object in which I am calling this sql using jdbc template.
The method takes in a list of String and that needs to be supplied to this SQl. I have my row-mapper.
How to write the SQl and how to pass the list of variables?
My SQL will run on a Teradata Db.
Use a NamedParameterJdbcTemplate which, as the doc says:
It also allows for expanding a List of values to the appropriate number of placeholders.
So you just need
String sql = "select * from Table1 where xyz in :list";
// or String sql = "select * from Table1 where xyz in (:list)";
// I can't remember which one is right
Map parameters = new HashMap<String, Object>();
parameters.put("list", theListOfXyz);
List<Foo> result = template.query(sql, parameters, rowMapper);
I just want to know how to create an instance of a Multipoint from a PostGIS database.
I do the query, then get a ResultSet named area. The column with MultiPolygon attributes is named geom, so I do the following:
MultiPolygon m = (MultiPolygon)area.getObject("geom");
Forced cast doesn't work though!
You shouldn't be referencing the ResultSet directly but should work through the datastore interface which takes care of the conversion for you. See the Query Tutorial for an example of searching a dataset and retrieving geometries.
You'll need something like:
SimpleFeatureSource source = dataStore.getFeatureSource(typeName);
FeatureType schema = source.getSchema();
String name = schema.getGeometryDescriptor().getLocalName();
Filter filter = CQL.toFilter(text.getText());
Query query = new Query(typeName, filter, new String[] { name });
SimpleFeatureCollection features = source.getFeatures(query);
I have an PostgreSQL Function which returns me an XML where the whole infos of my table are.
This is my function:
/* get all cat names */
create function cat_names() returns xml as $$
select to_xml('select name FROM cat_Infos;');
$$ language sql;
to get the results I do the following:
ResultSet rs = sql.executeQuery("select cat_names()");
while (rs.next()) {
// This is where I actually thought that I could pass the XML I get, to my DOMParser.
// I thought about something like this:
DOMParser dom = new DOMParser();
dom.setImputString(//Xml I get from the resultset)
}
The problem is, I actually have no idea how to get the Xml from the ResultSet.
You should be able to use
String xml = rs.getString(1)
to get the XML String