Let say I have multiple ResultSet(each resultSet would refer to 1 row in database) (they are of same table.) . Now I want to create consolidated ResultSet which would intern have all other resultSet. So my primary goal is to create a combined ResultSet which would point to all rows which where previously pointed by individual resultSet.
I am using Java. Do any one know how pragmatically we can achieve this?
Edit : we are using java.sql.ResultSet.
Edit : To make it more clear :
Let say I have
List<ResultSet> someResults ; // each resultSet Would point to a single row in database.
I want to create a consolidated ResultSet finalResults;
psudo code :
List<ResultSet> resultSets = // poppulated from code
ResultSet rs = convert(resultSets) // psude conver method
If you are talking about a java.sql.ResultSet, it's not possible as far as I know. I suggest you change your query instead.
Or you can retrieve the results into an java object and then combine all the objects into a Collection.
I would do it this way
class GatheringResultSet implements ResultSet {
List<E> resultSets;
ResultSet current;
GatheringResultSet(List resultSets) {
this.resultSets = new ArrayList(resultSets);
current = resultSets.remove(0);
}
#Override
public boolean next() throws SQLException {
if (current.next()) {
return true;
}
if (resultSets.isEmpty()) {
return false;
}
current = resultSets.remove(0);
return true;
}
...
the rest of the methods just delegate call to current ResultSet
If the results are gonna be from the same table, why not use UNION/UNION ALL(depending on your needs) in your query itself.
Something like this:
select A, B
from C where Q = R
union
select A, B
from C where P = S
Or else, there is the hard way of iterating through each result set and populating POJOs and adding them to a List/Set(Based on your needs). This seems to be an overkill if there are a lot of result sets.
public class ResultSets {
private java.util.List<java.sql.ResultSet> resultSets;
private java.sql.ResultSet current;
#lombok.SneakyThrows
public ResultSets(java.util.List<java.sql.ResultSet> resultSets) {
this.resultSets = new java.util.ArrayList<>(resultSets);
current = resultSets.remove(0);
}
#lombok.SneakyThrows
public boolean next() {
if (current.next()) {
return true;
}else if (!resultSets.isEmpty()) {
current = resultSets.remove(0);
return next();
}
return false;
}
#lombok.SneakyThrows
public int getInt(int pos){
return current.getInt(pos);
}
#lombok.SneakyThrows
public String getString(String field){
return current.getString(field);
}
}
Usage :-
#lombok.SneakyThrows
public static void main(String ... args) {
Connection conn = pe.getConnection("backup");
String sql1 = "SELECT count(distinct(User_Key)) FROM user_table";
String sql2 = "SELECT count(distinct(Username)) FROM user_table";
Statement stmt1 = conn.createStatement();
Statement stmt2 = conn.createStatement();
List<ResultSet> resultSets = new ArrayList<>();
resultSets.add(stmt1.executeQuery(sql1));
resultSets.add(stmt2.executeQuery(sql2));
ResultSets rs = new ResultSets(resultSets);
while(rs.next()){
System.out.println(rs.getInt(1));
}
}
Related
I am working with Datastax Java driver to read and write data into Cassandra. I am using datastax java driver 3.1.0 and my cassandra cluster version is 2.0.10.
I have created below two methods to execute my cql query.
I am calling first method when I don't need to set any value in my cql query so it works for cql string like below:
select * from testkeyspace.testtable where row_id=1 // cql-1
select * from testkeyspace.meta where row_id=1 // cql-2
select * from testkeyspace.proc where row_id=1 // cql-3
Now I need to call second method whenever I have query like this:
select * from testkeyspace.testtabletwo where row_id=1 and active=? // cql-4
select * from testkeyspace.storage where topic=? and parts=? // cql-5, in this part is Integer and topic is String.
So my question is how can I make my second method more generic so that if I need to set n number of values in my cql query using BoundStatement, it should work? Right now I am not sure what I am supposed to do for cql-4 and cql-5 while calling my second method with values passed to that method? I know I have to set those values using BoundStatement but if I need to set two or three or four value, how can I make that method generic so that I don't need to hardcode anything? Some can be Integer and some can be String.
First Method:-
public ResultSet executeQuery(final String cql) {
return executeWithSession(new SessionCallable<ResultSet>() {
#Override
public ResultSet executeWithSession(Session session) {
BoundStatement bs = getStatement(cql);
bs.setConsistencyLevel(consistencyLevel);
return session.execute(bs);
}
});
}
Second Method:-
public ResultSet executeQuery(final String cql, final Object... values) {
return executeWithSession(new SessionCallable<ResultSet>() {
#Override
public ResultSet executeWithSession(Session session) {
BoundStatement bs = getStatement(cql);
bs.setConsistencyLevel(consistencyLevel);
// how to set these **values** into my cql query using BoundStatement in a generic way
// so that I don't need to hardcode anything for cql-4 and cql-5
return session.execute(cql, values);
}
});
}
// cache the prepared statement
private BoundStatement getStatement(final String cql) {
Session session = getSession();
PreparedStatement ps = cache.get(cql);
// no statement cached, create one and cache it now.
if (ps == null) {
ps = session.prepare(cql);
PreparedStatement old = cache.putIfAbsent(cql, ps);
if (old != null)
ps = old;
}
return ps.bind();
}
Do I have to use BoundStatement here at all? I guess I have to because that's how I can set consistency level?
How about that:
public ResultSet executeQuery(final String cql, final Object... values) {
return executeWithSession(new SessionCallable<ResultSet>() {
#Override
public ResultSet executeWithSession(Session session) {
BoundStatement bs = getStatement(cql, values);
bs.setConsistencyLevel(consistencyLevel);
return session.execute(cql);
}
});
}
// cache the prepared statement
private BoundStatement getStatement(final String cql, Object... values) {
Session session = getSession();
PreparedStatement ps = cache.get(cql);
// no statement cached, create one and cache it now.
if (ps == null) {
ps = session.prepare(cql);
PreparedStatement old = cache.putIfAbsent(cql, ps);
if (old != null)
ps = old;
}
return ps.bind(values);
}
I am getting error in if(rs.next()) and .getString on my code. This is my code
public void keyPressed(KeyEvent e) {
Function f = new Function();
Result rs = null;
String ans = "Key";
rs = f.find(jTextField1.getText());
try{
if(rs.next()){
jTextArea1.setText(rs.getString("Key"));
}
}catch(Exception ex){
}
}
OK the methods next() and getString() are parts of the java.sql.ResultSet interface. Your code should look like this:
public void keyPressed(KeyEvent e) {
Function f = new Function();
ResultSet rs = null;
String ans = "Key";
rs = f.find(jTextField1.getText());
try{
if(rs.next()){
jTextArea1.setText(rs.getString("Key"));
}
}catch(Exception ex){}
}
And if the Function objects method find(String search) returns a valid java.sql.ResultSet implementation, you can use next() to move pointer to next Result and to check if it has one. And then you can easyly use getString(String columnName) to get the value of a column as String.
I would return ResultSet in an method like this. Let your Function class method find directly return your desired value or null or empty string. Handling the ResultSet here isn't good practice. Keep your concerns together.
I have the below class with 3 resultsets.
public class AllMetricsResultSet {
ResultSet top10Files;
ResultSet top10FilesForUsage;
ResultSet top10DataSet;
}
In another method, I have 3 different select statements(I've given only one select below, but there are 3) which assign result sets into the above.
public AllMetricsResultSet SPDataList (String alldata)
{
...........
String sSQL = "SELECT USERNAME, NUMBEROFFILES FROM FILE_INFO";
PreparedStatement stm = dbConnection.prepareStatement(sSQL);
if (stm.execute())
//TopTenantsForUsage = stm.getResultSet();
rs.top10Files = stm.getResultSet();
rs.top10FilesForUsage = stm.getResultSet();
rs.top10DataSet = stm.getResultSet()
Then finally from another method, I am calling the previous method as follows:
AllMetricsResultSet mrs = SPDataList(alldata);
while (mrs.top10Files.next())
(This while statement fails. I see that there are 10 rows returned. I tried mrs.top10Files.getFetchSize() (this also failed)
Any help would be greatly appreciated.
It's not a good practice to execute the queries in one method and read data from the result sets in a different method.
You want to finish your DB access as quick as possible and close the connection, in order to return the connection to the connection pool (relevant when you have multiple threads accessing the db) and release any db locks your statements may require.
Therefore the result set variables shouldn't br instance variables at all. You should create and consume them in the same method.
You could have, though, a separate method for each of your 3 queries, and each of them can return the data it fetched.
Instead try like this
public AllMetricsResultSet SPDataList (String alldata) {
String sSQL1 = "query1";
String sSQL2 = "query2";
String sSQL3 = "query3";
try {
PreparedStatement stm1 = dbConnection.prepareStatement(sSQL1);
PreparedStatement stm2 = dbConnection.prepareStatement(sSQL2);
PreparedStatement stm3 = dbConnection.prepareStatement(sSQL3);
if (stm1.execute())
top10Files = stm1.getResultSet();
if (stm2.execute())
top10FilesForUsage = stm2.getResultSet();
if (stm3.execute())
top10DataSet = stm3.getResultSet();
while (top10Files.next()) {
//get the resultset1 data
}
while (top10FilesForUsage.next()) {
//get the resultset2 data
}
while (top10DataSet.next()) {
//get the resultset3 data
}
// dont know why as you want to return the classType
//create an object of the class initialize it the the data you obtained
//and return it
}
catch(SQLException e)
{
e.printStackTrace();
}
finally {
//resultsetobject close
//statementObject close
//connection object close
}
}
I am currently learning JDBC and can successfully query and retrieve data from a MysQL database. But I would like to run this as a method and return the resultset rows from the method to the calling program.
So far I think I have made an appropriate method but am stuck returning the resultset as an object. Eclipse gives me the following error for the return type:
Object cannot be resolved to a type
Here is the method:
public object getAllPosts(int catID) throws Exception{
try{
this.catID = catID;
sql = "SELECT post_id, post_title, post_content, post_date FROM crm_posts WHERE cat_id = ? LIMIT ?";
prep = conn.prepareStatement(sql);
prep.setInt(1, catID);
prep.setInt(2, 3);
// execute statement
rs = prep.getResultSet();
} catch(Exception e){
e.printStackTrace();
}
return rs;
}
What is the return type I should use or is there a better way of doing this?
EDIT:
As stated in the comments it was a (annoying) typo. Object with a capital O.
If you're not going to return a ResultSet or Object object, then you should define your return type. You could create your own Post object for each row in the ResultSet, put those objects in a list, and return the list.
This is how you do it
public List<MyClassThatRepresentsTableInDatabase> getAllPosts(int catID) throws Exception{
try{
this.catID = catID;
sql = "SELECT post_id, post_title, post_content, post_date FROM crm_posts WHERE cat_id = ? LIMIT ?";
prep = conn.prepareStatement(sql);
prep.setInt(1, catID);
prep.setInt(2, 3);
// execute statement
rs = prep.getResultSet();
List<MyClassThatRepresentsTableInDatabase> ret=new ArrayList<>();
while(rs.hasNext()){
MyClassThatRepresentsTableInDatabase item=
new MyClassThatRepresentsTableInDatabase();
item.setId(rs.getLong("post_id");
item.setName(rs.getString("post_title");
item.setContentd("post_content");
//etc..
ret.add(item);
}
return ret;
} catch(Exception e){
e.printStackTrace();
}
return new ArrayList();
}
Excecute your query in ResultSet and loop it to get your results.
Use the following line of codes :
Statement st=conn.createStatement();
ResultSet rs=st.executeQuery(sql);
while(rs.next())
{
out.println(rs.getString("//Your Column name"));
}
I am trying to get all the results from multiple rows returned by the same where condition:
public static String getResult(String mycondition)
{
ResultSet rsData = sql.RunSelect("select col1 from my_table where con ='"+myCondition+"'");
if (rsData.next())
{
String result = rsData,getString("col1");
}
}
Note that there is an id column that makes these rows distinguishable.
The display in jsp page should make text fields for every row returned.
Any thoughts?
You can return a List<String> or use a char to separate the multiple strings in a single String. IMO it would be better returning a List<String>:
public static List<String> getResult(String mycondition) {
List<String> results = new ArrayList<String>();
ResultSet rsData = sql.RunSelect("select col1 from my_table where con='"
+myCondition+"'");
while (rsData.next()) {
results.add(rsData.getString("col1"));
}
return results;
}
Also, this method is prone to SQL Injection. Note that your parameters should be sent apart from the query. Probably you can improve your sql.RunSelect method to use PreparedStatement instead of Statement. This is a basic example of the code skeleton:
public ResultSet runSelect(String query, Object ... params) {
//assumes you already have your Connection
PreparedStatement pstmt = con.prepareStatement(query);
int i = 1;
for(Object param : params) {
pstmt.setObject(i++, param);
}
return pstmt.executeQuery();
}
So now you could modify your method to
public static List<String> getResult(String mycondition) {
List<String> results = new ArrayList<String>();
//using the new runSelect method
ResultSet rsData = sql.runSelect(
"select col1 from my_table where con=?", mycondition);
while (rsData.next()) {
results.add(rsData.getString("col1"));
}
return results;
}
you should use while loop instead of if loop
instead of - if (rsData.next())
use - while (rsData.next())
Although answer of #Luiggi Mendoza is best if you want security in your code