I am trying to pass the output of a ResultSet to Java HashMap.
Map<Integer, String> sIDpNumberHashMap = new HashMap<Integer, String>();
while (DBresult.next()) {
int sID = DBresult.getInt("slrid");
String pNumber = DBresult.getString("pNumber");
sIDpNumberHashMap.put(sID , pNumber );
System.out.println("Output1"+ sID + "\t" + pNumber + "\n");
}
System.out.println("Output2" + "\n" + sIDpNumberHashMap);
While the Output1 is showing all the records(from the DB). The put command only takes the last value from the ResultSet in.
Output1:
502332262 101E2571G103
502332262 101E2571G103
502332262 116E3139P001
502332262 117E3640G025
502332262 314B7159G003
502332262 117E3640G025
Output2:
{502332262=117E3640G025}
How do I make the put command to iterate over the results from the ResultSet?
All your IDs are identical (502332262), and HashMap doesn't allow duplicate keys. That's the reason you see only one entry in the HashMap (containing the last value you put in the Map).
If you want to allow duplicates, consider a different collection to hold the data. For example, you can use an ArrayList<SomeClass> where SomeClass contains the two properties you read from the DB.
I might be late but I believe someone can get an idea from what I did.
Recently I had an almost similar challenge where I wanted to build dynamic query results (whatever select query just returns its JSON list and question would vary a lot and I can't write method per query so I had to come up with something everyone will be calling).
Below is my sample code:
public <T> List<T> findWithDynamicQuery(String query){
Connection conn = null;
PreparedStatement statement = null;
List<Object> mResults = new ArrayList<>();
try {
conn = //use your connection parameters;
} catch (SQLException e) {
e.printStackTrace(out);
return (List<T>) mResults;
}
try {
statement = conn.prepareStatement(query);
ResultSet result = statement.executeQuery();
ResultSetMetaData metaData = result.getMetaData();
int column = metaData.getColumnCount();
while (result.next()) {
HashMap<Object, Object> rows = new HashMap<>();
for(int i = 1; i <= column; i++){
rows.put(metaData.getColumnLabel(i), result.getObject(i));
}
mResults.add(rows);
}
result.close();
return (List<T>) mResults;
} catch (SQLException e) {
e.printStackTrace(out);
}finally{
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
}
}
}
return (List<T>) mResults;
}
Related
I have a code that reads from an SQL Database and saves each column of information into an ArrayList. I need to pass each ArrayList into a separate class where I can store the lists as single pieces of information (IE: Information in the first part of ArrayList1 goes with information in the first part of ArrayList2 etc...) and then sort them. I don't know how to pass that information to another class though. This is a section of my main method that stores the information into a list. I need this information passed to a separate class called List.java:
String SelectStatement1 = "SELECT InvoiceID FROM Invoice;";
ps = conn.prepareStatement(SelectStatement1);
rs = ps.executeQuery();
int count = 0;
while (rs.next()){
count++;
}
ps.close();
ps = conn.prepareStatement(SelectStatement1);
rs = ps.executeQuery();
ArrayList<String> InvoiceIDList = new ArrayList<String>();
String InvoiceID = null;
int p = 0;
while (p < count){
rs.next();
InvoiceID = rs.getString("InvoiceID");
InvoiceIDList.add(InvoiceID);
p++;
}
ps.close();
p = 0;
Edit: This is only a section of my code, I already have the code open and close the connections, I only need information on how to pass the ArrayList to another class for sorting.
Create a method in your other class like this:
public void receiveList (ArrayList<String> invoiceIDList) {
// Do something with invoiceIDList data
}
It may not be a bad idea to create a constructor in your "List" class, that accepts the ArrayList and creates the class instance with the required data
Also, please change the name of that class!! It will be confusing to others who read your code, as you are passing an ArrayList already!
EDIT:
You could also have your class implement the List interface, which would make things a lot easier for you, because you can insert data into your class based on the position of the data in the ArrayList.
public class yourClass implements List<String> {
// Your class methods and variables...
}
If you wanted to expand on this to allow more than just Strings, you can change to: List<T>, this would give you a more generic approach.
First, I suggest you perform a SELECT COUNT() instead of iterating your rows in your first query. Then remember to close() both the PreparedStatement and ResultSet. Finally, I would suggest you program to the List<String> interface. Putting it all together like,
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Connect to your database and initialize conn.
int count = 0;
try {
String query1 = "SELECT COUNT(InvoiceID) FROM Invoice;";
ps = conn.prepareStatement(query1);
rs = ps.executeQuery();
if (rs.next()) {
count = rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
} catch (Exception ignored) {
}
try {
ps.close();
} catch (Exception ignored) {
}
}
The above block of code is necessary to close() both rs and ps in the correct order with the finally Block.
List<String> invoiceIdList = new ArrayList<>();
try {
String query2 = "SELECT InvoiceID FROM Invoice;";
ps = conn.prepareStatement(query2);
rs = ps.executeQuery();
while (rs.next()) {
invoiceIdList.add(rs.getString("InvoiceID"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally { // <-- it's identical to the finally block above.
try {
rs.close();
} catch (Exception ignored) {
}
try {
ps.close();
} catch (Exception ignored) {
}
}
// now you can pass invoiceIdList elsewhere...
if (!invoiceIdList.isEmpty()) {
doSomething(invoiceIdList);
}
I have faced a scenario, the task was to read a file which contains 3 Millions IP Address.
There is MySQL Table which contains Id,PrimaryIP, PrimaryIP can by multiple IP separated by #, more over that PrimaryIP can also contain CIDR IP.
So totally, there are 8000 records, each record with multiple IP and CIDR IP.
Now, my task was to read that file, check it against with database and write the matching IP,ID to a file.
Initially, when i run my program, my program failed because: java.lang.OutOfMemoryError: Java heap space, so i have increased it by 3GB, still it was failing, then later i split the file into 6 subfiles, as 0.5 Millions each.
To find CIDR IP List, i have used Apache SubnetUtils.
Below is my code :
public static void main(String[] args) {
String sqlQuery = "SELECT id,PrimaryIP from IPTable where PrimaryIP != '' limit 100000;";
Connection connection = null;
Statement statement = null;
File oFile = new File("output.txt");
System.out.println(new Date());
try{
List<String> fileData = FileUtils.readLines(new File("input.txt"));
System.out.println("File Data Size : "+fileData.size());
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost/db?user=root&password=pwd");
statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sqlQuery);
System.out.println("Started with MySQL Querying");
Map<String, Integer> primaryIPIDMap = new HashMap<String, Integer>();
while (resultSet.next()) {
primaryIPIDMap.clear();
int recordID = resultSet.getInt(1);
if (resultSet.getString(2).contains("#")) {
String primaryIP[] = resultSet.getString(2).split("#");
for (int i = 0; i < primaryIP.length; i++) {
if (primaryIP[i].contains("/")) {
String allIP[] = getAllIP(primaryIP[i]);
for (int allIPi = 0; allIPi < allIP.length; allIPi++) {
primaryIPIDMap.put(allIP[allIPi].intern(), recordID);
}
} else {
primaryIPIDMap.put(primaryIP[i].intern(), recordID);
}
}
} else {
primaryIPIDMap.put(resultSet.getString(2).intern(), recordID);
}
Iterator entries = fileData.iterator();
while (entries.hasNext()) {
String t = (String) entries.next();
if (primaryIPIDMap.containsKey(t)) {
FileUtils.writeStringToFile(oFile, recordID + "," + t);
}
}
primaryIPIDMap.clear();
}
resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (statement != null)
statement.close();
} catch (Exception se2) {
}
try {
if (connection != null)
connection.close();
} catch (Exception se) {
se.printStackTrace();
}
}
System.out.println("Finished");
System.out.println("End Time : "+new Date());
}
private static String[] getAllIP(String ip) {
return new SubnetUtils(ip).getInfo().getAllAddresses();
}
Can someone tell me the best practice to solve this.
Today it just 3 Millions, tomorrow it may be 5 Millions. I can't keep on creating subfile.
I fixed the problem using
Reading the input file line-by-line
I didn't change MySQL Table structure because it has a dependency in many places and table was not designed by me.
i am getting some records from database and adding in HashMap<Integer, Object> .Then i am adding this HashMap to a Vector<HashMap<Integer, Object>>. Now problem is when. I am printing the Vector, I am not getting the records in the same insertion order ... Please help.
public Vector<HashMap<Integer, Object>> executeQueryAsIntegerColumnNames(String aQuery, HashMap<String,String> conditions, String likeQuery){
LOGGER.info("Query in Execute:"+aQuery);
LOGGER.info("Query in Execute:"+conditions);
LOGGER.info("Query in Execute:"+likeQuery);
Vector <HashMap<Integer,Object>> result = null;
Connection conn = connection.getMySQLConnection();
String concond = this.getConditions(conditions);
try {
Statement stmt = conn.createStatement();
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(aQuery + concond);
ResultSetMetaData metaInfo = null;
if(rs != null){
metaInfo =rs.getMetaData();
}
while(rs != null && rs.next()){
if(result == null){
result = new Vector<HashMap<Integer, Object>>();
}
HashMap<Integer, Object> row = new HashMap<Integer, Object>();
for(int i = 1 ; i <= metaInfo.getColumnCount(); i++){
row.put(i, rs.getObject(i));
}
result.add(row);
}
}catch(Exception ex){
LOGGER.error("executeQueryAsIntegerColumnNames : "+ex);
}finally{
try {
conn.close();
} catch (SQLException e) {
LOGGER.error("Exception :",e);
}
}
LOGGER.info("Befor Returning to Caller : "+result.toString());
return result;
}
Does Vector support insertion Order??? IF YES then This is my OutPut Please have a look
Befor Returning to Caller : [{1=mah0300537, 2=nabi hussain, 3=Mah03, 4=05:50:00 PM, 5=233346, 6=0}, {1=cha0700003, 2=sita sharan ray, 3=cha07, 4=05:50:00 PM, 5=233347, 6=2}]
Befor Returning to Caller : [{1=cha0700003, 2=sita sharan ray, 3=cha07, 4=05:50:00 PM, 5=233347, 6=2}, {1=mah0300537, 2=nabi hussain, 3=Mah03, 4=05:50:00 PM, 5=233346, 6=0}]
HashMap doesn't maintain insertion order. Use LinkedHashMap instead.
From HashMap javadoc:
This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
Use LinkedHashMap if you want to keep the order of inserted elements in a map.
If you have to maintain order use LinkedHashMap .
http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
I want to count the numbers of entries in resultset and then store these values in an array and pass this array to create a graph.
ResultSet rs = stmt.executeQuery( "SELECT distinct "+jTextField.getText()+" as
call from tablename"); // this statement will select the unique entries in a
particular column provided by jtextfield
int count=0;
while(rs.next())
{ ++count; } // This will count the number of entries in the result set.
Now I want to store the values of result set in an array of string. I used the following code
String[] row = new String[count];
while(rs.next())
{
for (int i=0; i <columnCount ; i++)
{
row[i] = rs.getString(i + 1);
}
}
Error : Invalid Descriptor Index.
Please suggest how to copy the result of resultset in array.
For example if I enter priority in jTextField , the result set will contain
priority1
priority2
priority3
In your first while loop you read all the entries in the ResultSet, so when executing the second while loop there's nothing else to read. Also, the index of ResultSet#getXxx starts at 1, not at 0. Also, since you don't know the amount of rows that you will read, it will be better using a List backed by ArrayList instead.
Considering these, your code should look like:
ResultSet rs = stmt.executeQuery( "SELECT distinct "+jTextField.getText()+
" as call from tablename");
List<String> results = new ArrayList<String>();
while(rs.next()) {
results.add(rs.getString(1));
}
Based in your comment, I extended the sample:
public List<String> yourRandomQuery(String columnName) {
Connection con = null;
ResultSet rs = null;
List<String> results = new ArrayList<String>();
try {
String baseQuery = "SELECT DISTINCT %s AS call FROM tablename";
con = ...; //retrieve your connection
ResultSet rs = stmt.executeQuery(String.format(baseQuery, columnName));
while(rs.next()) {
results.add(rs.getString(1));
}
} catch (SQLException e) {
//handle your exception
e.printStacktrace(System.out);
} finally {
closeResource(rs);
closeResource(con);
}
return results;
}
//both Connection and ResultSet interfaces extends from AutoCloseable interface
public void closeResource(AutoCloseable ac) {
try {
if (ac != null) {
ac.close();
}
} catch (Exception e) {
//handle this exception as well...
}
}
public void someMethod() {
//retrieve the results from database
List<String> results = yourRandomQuery(jTextField.getText());
//consume the results as you wish
//basic example: printing them in the console
for(String result : results) {
System.out.println(result);
}
}
Try this
ResultSet rs = stmt.executeQuery( "SELECT distinct "+jTextField.getText()+" as
call from tablename");
List<String> list=new ArrayList<>();
while(rs.next())
{
list.add(rs.getString(1));
}
Why not just create a HashSet<String> and write into that. Note that HashSet is unordered, just like your query. By using a collection that is of arbitrary size you don't need to determine the require dsize in advance.
I'm using Spring-orm and HibernateTemplate to execute a native SQL query (DB is Oracle 11 for the reference), like this:
#Override
public List<Object> executeNativeQuery(final String queryStr, final Map<String, String> params) {
List<Object> results = this.template.execute(new HibernateCallback<List<Object>>() {
#Override
public List<Object> doInHibernate(Session session) throws HibernateException, SQLException {
// Get the query
Query query = session.createSQLQuery(queryStr);
// Assign parameters to the query, if any
if (params != null) {
for (Map.Entry<String, String> entry : params.entrySet()) {
query.setString(entry.getKey(), entry.getValue());
}
}
// fire the query
#SuppressWarnings("unchecked")
List<Object> res = query.list();
return res;
}
});
return results;
}
I've managed to successfully execute the query and get the results back. But I couldn't figure out a way to also get the resulting column names, and I'm starting to think that's not possible using this approach.
My problem is that I have to execute a query that comes from user input and I have no clues about parameter names.
Any ideas?
I finally found a way through it, so I post it hoping it'll be useful for others. I was doing it the wrong way, the correct way (at least for what my needs are) is to use doWork.
instad of:
session.createSQLQuery(queryStr);
I had to get the connection like this:
session.doWork(new Work() {
#Override
public void execute(Connection con) throws SQLException {
try {
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(queryStr);
ResultSetMetaData md = rs.getMetaData();
int col = md.getColumnCount();
System.out.println("Number of Column : " + col);
System.out.println("Columns Name: ");
for (int i = 1; i <= col; i++) {
String col_name = md.getColumnName(i);
System.out.println(col_name);
}
} catch (SQLException s) {
System.out.println("SQL statement is not executed!");
}
}
});
Try the following to get column names in Hibernate:
public ArrayList<String> getTableDesc(String tableName){
System.out.println("getFieldNames:start"+tableName);
Object[] a;
List<Object[]> fieldNames = new ArrayList<Object[]>();
ArrayList<String> tabFieldNames = new ArrayList<String>();
Session session = getHibernateTemplate().getSessionFactory().openSession();
try{
String queryStr = "desc "+tableName;
fieldNames = (List<Object[]>) session.createSQLQuery(queryStr).list();
for(int i=0;i<fieldNames.size();i++){
a = fieldNames.get(i);
tabFieldNames.add(a[0].toString());
}
}
catch(Exception e){
System.out.println("exception "+e);
}
finally{
session.close();
}
System.out.println("getFieldNames:end"+tabFieldNames.toString());
return tabFieldNames;
}
You can use ResultTransformer class to map the query result to an entity class.
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/querysql.html#d0e17313
EDIT 1:
for( int i= 0; i< ((Object[])res.get(0)).length ; i++){
//do something with data
res.get(0)[i]
}