Sorting data in ResultSet Java - java

I have obtained a ResultSet for some query, e.g:
select * from students order by roll
Now, is it possible to perform an equivalent of query
Select * from students order by dob;`
on the ResultSet?

As rule of thumb (well, almost) everything that can be done in the DB should be done there, so you should sort your data in the DB using the ... ORDER BY <column1>, <COLUMN2>... ASC/DESC
But if for some reason you cannot do that you should extract all the data from the RS into a collection (and may be map your data to domain objects) and sort it using the Collections.sort() method with an appropriate Comparator

It will be very not recommended to do the Sort after the query (ie. When you're getting the ResultSet).
You should always aim to do actions on the SQL Server rather on the code itself.
ResultSet are some kind of Iteration objects, that means that you can only move one by one. Thus, in order to Sort it, you first need to shift the data into a Collection and only then use Sorting on it.
Compare to SQL Sorting this is overhead and can be avoided.

Get an ArrayList from your ResultSet by iterating over your result and adding it to a a new list.
Then useCollections.sort(Collection, Comparator) to sort your result

Related

How can i reverse a read-only-list in java?

I'm having a problem reversing a list object that is fetched from a database using jpa.
I'm using Collections.reverse(myListObject).
What I intend to do is to retrieve the list from database, reverse it, then send it to my jsp page.
I get the below error:
"java.lang.UnsupportedOperationException: Result lists are read-only."
Any solution for this?
Since the list is coming from JPA, the first approach is to avoid reversing the list in memory, doing it on RDBMS side instead. Change the ORDER BY clause of your JPQL if this approach is viable in your situation.
If this cannot be done, for example, because you have no direct control over your JPQL, reverse a copy:
List<MyType> rev = new ArrayList<MyType>(myListObject);
Collections.reverse(rev);

Encapsulating JDBC resultset

I have a very common encapsulation problem. I am querying a table through jdbc and needs to hold the records in memory for sometime for processing.I dont have any hibernate POJO for the same table to create any objects and save.I am talking about a load of say 200 million in a single query.
The common approach is to create an object array and do casting when I need to use them. (Assume, I can get the table details like column name and data type which will be saved in some reference tables..) But this approach will be very expensive (Time) I guess when the load is taken into consideration..
Any good approach will be appreciated...
Sounds like a CachedRowSet would do the trick here. That's pretty much exactly what you want. It will take a ResultSet and suck the entire thing down, then you can work on it at your leisure.
Addenda:
I am really looking for a robust record holder with easy access on the members
But that's pretty much exactly what a CachedRowSet is.
It manages a collection of records with named (and numbered) columns, and provides typed access to those columns.
CachedRowSet crs = getACachedRowSet();
crs.absolute(5) // go to 5th row, shows you have random access to the contents.
String name = crs.getString("Name");
int age = crs.getInt("Age");
date dob = crs.getDate("DateOfBirth");
While I'm sure you can make up something on your own, a CachedRowSet gives you everything you've asked for. If you don't want to actually load the data in to RAM, you could just use a ResultSet.
Only down side is that it's not thread safe, so you'll need to synchronize around it. But that's life. How exactly does a CachedRowSet not meet your needs?
Well, if you need 200m objects in memory then you can initialize each while iterating through the ResultSet - you don't need to save the metadata
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
String col1= rs.getString("col1");
Integer col2= rs.getInt("col2");
MyClass o = new MyClass(col1,col2);
add(o);
}
rs.close();
To make it more clear, the table involved is completely configurable.
That is why I cant create POJO classes prior to this task.
In that case, I'd have thought that the only real way of doing this is to turn each row into a string with delimiters (CSV, XML or something) and then create an array of strings.
You can get a list of column names returned by a JDBC query as in this answer:
Retrieve column names from java.sql.ResultSet

Advice on JDBC ResultSet

I have Employee table and an Entity class for it,
My task is such that i need the data of employee table within result set(of type scrollable) two times,
in such case what would be better of the following for using the data second time ->
1: create instance of entity class and store it in List while iterating through result set for first time.
OR
2: after first iteration call the first() method of result set to go back to first row and use data for second time.
Which option will consume less time and resources.
If You have better suggestions, please provide.
Thanks.
Unless this is about very large resultsets, you're probably much better off consuming the whole JDBC ResultSet into memory and operating on a java.util.List rather than on a java.sql.ResultSet for these reasons:
The List is more user-friendly for developers
The database resource can be released immediately (which is less error-prone)
You will probably not run out of memory in Java on 1000 rows.
You can make many many mistakes when operating on a scrollable ResultSet, as various JDBC drivers implement this functionality just subtly differently
You can use tools for consuming JDBC result sets. For instance Apache DbUtils:
QueryRunner run = new QueryRunner(dataSource);
ResultSetHandler<List<Person>> h
= new BeanListHandler<Person>(Person.class);
List<Person> persons = run.query("SELECT * FROM Person", h);
jOOQ (3.0 syntax):
List<Person> list =
DSL.using(connection, sqldialect)
.fetch("SELECT * FROM Person");
.into(Person.class);
Spring JdbcTemplate:
JdbcTemplate template = // ...
List result = template.query("SELECT * FROM Person", rowMapper);
Cache the data you retrieve from database. It's always better than polling it, even if driver provides caching on its own level. You can always withdraw it if it's not needed anymore.
Maybe using a Map of employees by their primary key would help?
If You'd describe why You think You need to iterate the list more than once, than we'd see if there's a better algorithm there to get rid of that second interation in the first place.

iBatis using a set for a resultMap as well as a parameterMap

I want to pass a Set of Strings in an iBatis query for the parameter map as well as return a collection of strings for the result set.
Is this possible?
Example queries ...
SELECT * FROM some_table t WHERE t.some_column IN (values);
UPDATE some_table t SET t.some_column = 'some_value' WHERE t.other_column IN (values);
Walter
If you want to pass a List of Strings as one parameter, for example for building a IN(val1,val2...) query, then you should read about dynamic queries, in particular the Iterate element. See also.
For the return, In SqlMapClientTemplate there is the queryForList method.
As for the Set of String as parameter, I do not know if iBatis handles that; we built an object for that, and when I faced that problem it was in a sql in clause, so I made a loop with comma separated values.
Or you can convert the Set to an HashMap and pass that.

Building resultset using collection object

I had an issue in building the resultset using Java.
I am storing a collection object which is organized as row wise taken from a resultset object and putting the collection object (which is stored as vector/array list) in cache and trying to retrieve the same collection object.
Here I need to build back the resultset again using the collection object. Now my doubt is building the resultset in this way possible or not?
The best idea if you are using a collection in place of a cache is to use a CachedRowSet instead of a ResultSet. CachedRowSet is a Subinterface of ResultSet, but the data is already cached. This is far simpler than to write all the data into an ArrayList.
CachedRowSets can also be queried themselves.
CachedRowSet rs;
.......................
.......................
Integer id;
String name;
while (rs.next())
{
if (rs.getInt("id") == 13)
{
id = rs.getInt("id");
name = rs.getString("name"));
}
}
So you just call the CachedRowSet whenever you need the info. It's almost as good as sliced bread. :)
EDIT:
There are no set methods for ResultSet, while there are Update methods. The problem with using the Update method's for the purpose of rebuilding a ResultSet is that it requires selecting a Row to update. Once the ResultSet has freed itself, all rows are set to null. A null reference cannot be called. A List of Lists mimics a ResultSet itself, or more correctly, an array of arrays mimic a ResultSet.
While Vectors are thread safe, there is a huge overhead attached to them. Use the ArrayList instead. As each nested List is created and placed into the outer nest List, insert it in this manner.
nest.add(Collections.unmodifiableList(nested));
After all of the nested Lists are inserted, return the nest List as an umodifiableList as well. This will give you a thread-safe collection without the overhead of the vectors.
Take a look at this page. Try to see if the SimpleResultSet class is fine for your needs.
If you combine its source into a standalone set of classes, it should do the trick.
From what I could get, your code may be like this:
List collection = new ArrayList();
collection.add(" A collection in some order");
List cache = new ArrayList();
cache.add(collection); ...
Now when you retrieve I think you'll get your collection in order, since you have used List.
If this is not what you were expecting, do comment.
I will advise you to use CachedRowSet. Refer http://www.onjava.com/pub/a/onjava/2004/06/23/cachedrowset.html this article to know more about CachedRowSet. Once you create this CachedRowSet, you can disconnect from the database, make some changes to the cached data and letter can even open the DB connection and commit the changes back to the Database.
Another option you should consider is just to refactor your code to accept a Collection instead of a ResultSet.
I'm assuming you pass that ResultSet to a method that iterates over it. You might as well change the method to iterate over an ArrayList...

Categories

Resources