1

In java i would do something like below to iterate the resultset and form the query,

public Map<String, List<MODEL>> fun(){
Map<String, List<MODEL>> map = new TreeMap<String, List<MODEL>>();      
        LinkedHashSet<String> set = new LinkedHashSet<String>();

            String sql = "select distinct(column) from table where conditions orderby column ";
            ResultSet rslt = stmt.executeQuery(sql);
            while (rslt.next()) {
                al.add(rslt.getString(1));
            }
            for (String s : al) {           
                List<MODEL> list = new ArrayList<MODEL>();
                String sql2 = "select * from table where column="+s;
                ResultSet rslt2 = stmt.executeQuery(sql2);
                while (rslt2.next()) {
                    MODEL obj = new MODEL();
                    // set values to setters from resultset
                    list.add(obj);
                }
                map.put(s, list);
            }
            return map;
            }

the reason why i have used the separate query is , i am adding the distinct values to the map key and their corresponding values(as List) to the values of the map .NOTE (In the result it has duplicate values of the column1) , But i need to store them as map key and hence making it as unique . also i need all its associated values so populating a list

How can i achieve the same functionality using JdbcTemplate ,

Thanks in advance

Santhosh
  • 8,181
  • 4
  • 29
  • 56
  • 2
    What you are doing is not a good idea to do with regular JDBC code! The performance suffers from repeatedly querying the database. You'd be better off using a join query and then extracting the relevant data. It goes without saying that to transfer your JDBC code to Spring using RowMapper like you propose, would be even worse. A RowMapper should be a dumb object that creates DTOs. Nothing more – geoand Aug 20 '14 at 12:54
  • yes i know , but the requirement has the above chance alone . And i am sure that the first query will contain only 3 to 4 results . so that wont cause performance issue . is there a way to do it using spring jdbc? – Santhosh Aug 20 '14 at 13:00
  • Even consider that i am adding my result set to the set and am iterating it again – Santhosh Aug 20 '14 at 13:06
  • 1
    I strongly suggest merging both queries into one query `select * from table where column in (select distinct(column) from table)` you can then use a `RowMapper` to map the actual results. Instead of 5 queryies you are now doing one and have simplified your code. – M. Deinum Aug 20 '14 at 13:15
  • so is it possible to get the 2nd query result if i merge them `(select distinct(column) from table)` . what i need is a map with key as 2nd part of the query you formed and the values of the first part of the query – Santhosh Aug 20 '14 at 13:19
  • 1
    One observation: Your query lets be attacked by SQL Injection. Is a bad practice has something attached in the query `+rs.getString(1)` use the `setParameter` method(s) instead. JdbcTemplate has support to do that. – Manuel Jordan Aug 20 '14 at 13:21
  • @ManuelJordan thanks will change to prepared statements – Santhosh Aug 20 '14 at 13:22
  • you could make the rowmapper a spring-managed bean, and inject a dao into it. it would be nasty but definitely possible. – Nathan Hughes Aug 20 '14 at 13:24
  • @NathanHughes thanks for your comment . any similar examples or so questions . i will edit my question make it a bit clear – Santhosh Aug 20 '14 at 13:25
  • @NathanHughes i have edited my post , please check it now . it is the exact thing i wish do with `jdbc template` . is it possible ? – Santhosh Aug 21 '14 at 08:59

2 Answers2

2

As stated by multiple people your solution isn't efficient although it might work you are basically falling into the trap of the 1+N select problem. 1 query to retrieve some id and next for each id another query (hence 1+N select).

It would be better to just write a single query which retrieves everything in one go. Looking at your code you have the following 2 queries which, by the looks of it, operate on the same table.

String sql1 = "select distinct(column) from table where conditions orderby column ";
String sql2 = "select * from table where column="+s

Now you can either make the first query a subselect for the second query

String sql = "select * from table where column in (select distinct(column) from table where conditions) order by column";

However, again from the looks of it, it would also be possible (or maybe even easier) to just put the where clause in your second query.

String sql = "select * from table where conditions order by column";

You will now, possibly, get for your key (in the Map) get multiple values. You can do two things either use a ResultSetExtractor loop over the results yourself or use a RowCallbackHandler which does the iteration for you.

What you need to do is just iterate of the results (or let the JdbcTemplate do that for you) for you key column check the Map if a List is already there. If it is add a row if it isn't first create the List and add it to the result Map.

public Map<String, List<MODEL>> fun(){
    final Map<String, List<MODEL>> map = new TreeMap<String, List<MODEL>>();      

    String sql = "select * from table where conditions order by column";
    getJdbcTemplate().query(sql, new RowCallbackHandler() {
        public void processRow(ResultSet resultSet) throws SQLException {
            String key = rs.getString("column");
            List rows = map.get(key);
            if (rows == null) {
                rows = new new ArrayList<MODEL>();
                map.put(key, rows);
            }
             MODEL obj = new MODEL();
            // set values to setters from resultset
            rows.add(obj);
        }, "arguments"); 
    return map;
}

Another solution, which would only work if the 'column' is also part of the MODEL class. That way you could use a RowMapper and get a List of all MODEL objects and do the partitioning afterwards. You could use Google Guava to make it a little easier to do that or if you are on Java 8 you could use the new streams api for that.

Community
  • 1
  • 1
M. Deinum
  • 115,695
  • 22
  • 220
  • 224
1

As @geoand said, the best thing (whether in straight JDBC code or using JDBCTemplate) would be to do a single query with a Join.

If, however, as you mentioned in the comments, you are absolutely certain that the result set from the first query will always be small (doubtful), then you could store the values retrieved from the first query in a list, and then do a second query with an "in" clause, using the list as a parameter. This would result in two queries.

In any case, you really don't want to do a separate query for each item returned from the first query, as this will be quite slow, even for small numbers of items. But, if you feel that you must, then store the results of the first query in a list, and then issue another query for each item in the list.

TLDR; No, JDBCTemplate does not provide a mechanism for doing what you want, mostly because it's generally considered to be a canonical example of a programming anti-pattern.

GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67
  • Well actually `JdbcTemplate` does provide such a mechanism by using a `ResultSetExtractor`. Which you could use to iterate yourself and execute a query again, not that I would advice it but alas. – M. Deinum Aug 20 '14 at 13:15
  • @M.Deinum the final result i need is something like this `Map` And the reason i needed to i may have duplicates of 1st query result . but i need the single value – Santhosh Aug 20 '14 at 13:17
  • Judging from the code you posted you cannot have duplicates as you used a distinct. – M. Deinum Aug 20 '14 at 13:18
  • ok . but is it possible to get the values of the 2nd part of the query also there may be many entries for the `select distinct(column) from table` , the reason i use distinct is i get the unique values for the key . And in the second query i use it to get the all values associated with `distinct(column)` – Santhosh Aug 20 '14 at 13:24
  • @M.Deinum i have edited my post , please check it now . it is the exact thing i wish do with `jdbc template` . is it possible ? – Santhosh Aug 21 '14 at 08:59