How can I get the value of HashTable inside the arrayList?
I have the following code:
public ArrayList resultSetToArrayList(ResultSet rs) {
ArrayList list = new ArrayList();
try {
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
int rowcount = 0;
while (rs.next()) {
Hashtable row = new Hashtable();
for (int i = 1; i <= columns; ++i) {
row.put(md.getColumnName(i), rs.getString(i));
}
list.add(rowcount, row);
rowcount++;
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
You appear to be using raw types and Hashtable instead of a HashMap. I think you're asking for something like
public List<Map<String, String>> resultSetToArrayList(ResultSet rs) {
List<Map<String, String>> list = new ArrayList<>();
try {
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
while (rs.next()) {
Map<String, String> row = new HashMap<>();
for (int i = 1; i <= columns; ++i) {
row.put(md.getColumnName(i), rs.getString(i));
}
list.add(row);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
As for getting the values back out of a Map, you might iterate the Map.keySet() like
for (String key : map.keySet()) {
System.out.printf("%s = %s%n", key, map.get(key));
}
Related
So I'm trying to store a MySQL query result set into a multi dimensional HashMap as listed so:
public HashMap<String, HashMap<String, String>> getData(String query)
{
Statement stmt = null;
HashMap<String, HashMap<String, String>> results = new HashMap<String, HashMap<String, String>>();
try
{
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
ResultSetMetaData rsmd = rs.getMetaData();
while (rs.next())
{
for (int i = 1; i < rsmd.getColumnCount() + 1; i++)
{
results.put(Integer.toString(i - 1), new HashMap<String, String>());
results.get(Integer.toString(i - 1)).put(rsmd.getColumnLabel(i), rs.getString(i));
}
}
}
catch (SQLException ex)
{
ex.printStackTrace(System.out);
}
return results;
}
However when using the function to print it out as so:
public static void printMap(Map mp)
{
Iterator it = mp.entrySet().iterator();
while (it.hasNext())
{
Map.Entry pair = (Map.Entry)it.next();
System.out.println(pair.getKey() + " = " + pair.getValue());
it.remove();
}
}
It is only storing a single row result and I can't wrap my head around why.
0 = {Date=2014-11-04}
1 = {Num=1256}
2 = {ATime=null}
3 = {ALocCode=null}
4 = {DTime=1:00 PM}
5 = {DLocCode=JFK}
6 = {EstATime=8:00 PM}
7 = {EstDTime=1:00 PM}
8 = {EId=7624}
My question is, and the only way I can put it is relating to PHP, is how can I make it store like this?
$result[0]['Date'] = '3214';
....
$result[1]['Date'] = '6426';
Since that is essentially what I'm trying to achieve?
main problem that you've swapped "rows" and "columns", next one is that you're re-creating HashMap every time you put field, proper code will look like this:
public Map<String, Map<String, String>> getData(final String query) {
final Map<String, Map<String, String>> results = new HashMap<>();
try (final Statement stmt = this.conn.createStatement(); final ResultSet rs = stmt.executeQuery(query);) {
final ResultSetMetaData rsmd = rs.getMetaData();
long rId = 0;
while (rs.next()) {
final Map<String, String> record = new HashMap<>();
for (int i = 1; i < (rsmd.getColumnCount() + 1); i++) {
record.put(rsmd.getColumnLabel(i), rs.getString(i));
}
results.put(String.valueOf(rId++), record);
}
} catch (final SQLException ex) {
ex.printStackTrace(System.out);
}
return results;
}
public static void printMap(final Map<?, ?> mp) {
for (final Entry<?, ?> entry : mp.entrySet()) {
final Object key = entry.getKey();
final Object value = entry.getValue();
if (value instanceof Map) {
System.out.println(key);
printMap((Map<?, ?>) value);
} else {
System.out.println(key + "=" + entry.getValue());
}
}
}
The answer by Lashane is good for the errors you needed solving, however it can be improved:
You wanted numeric access ($result[0]['Date']) to the rows, not string.
print method should use fully typed parameter.
Rows should be stored in TreeMap or LinkedHashMap or ArrayList to retain row order. ArrayList is better for your case, actually.
Columns should be stored in LinkedHashMap to retain column order.
Do not catch exception and continue. Allow it to cascade up to caller.
Updated version:
public List<Map<String, String>> getData(final String query) throws SQLException {
final List<Map<String, String>> results = new ArrayList<>();
try (Statement stmt = this.conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) {
ResultSetMetaData metaData = rs.getMetaData();
while (rs.next()) {
Map<String, String> record = new LinkedHashMap<>();
for (int col = 1; col <= metaData.getColumnCount(); col++)
record.put(metaData.getColumnLabel(col), rs.getString(col));
results.add(record);
}
}
return results;
}
public static void printMap(List<Map<String, String>> rows) {
for (int rowNum = 0; rowNum < rows.size(); rowNum++)
System.out.println(rowNum + " = " + rows.get(rowNum));
}
You can now access it like you did in PHP:
// PHP (for reference, the way you requested)
$result[0]['Date']
// Java
result.get(0).get("Date")
// Groovy
result[0]['Date']
result[0].Date
// JSP
<c:forEach var="row" items="${result}" varStatus="rowStatus">
${rowStatus.index} = <c:out value="${row.Date}"/>, ...
</c:forEach>
Currently I got the following problem:
I load the TableModel data from a H2 database like so:
public static DefaultTableModel loadTableModel(ResultSet rs)
throws SQLException {
// names of columns
Vector<String> columnNames = new Vector<String>();
int columnCount = Definitions.COLUMN_NAMES.length;
for (String string : Definitions.COLUMN_NAMES) {
columnNames.add(string);
}
// data of table
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
while (rs.next()) {
Vector<Object> vector = new Vector<Object>();
for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
if (rs.getObject(columnIndex).getClass() == Integer.class) {
if ((int) rs.getObject(columnIndex) == 0) {
vector.add(null);
} else {
vector.add(rs.getObject(columnIndex));
}
} else {
vector.add(rs.getObject(columnIndex));
}
}
data.add(vector);
}
return new DefaultTableModel(data, columnNames);
}
By doing so I pass over the data from my database and columnNames to the constructor of the DefaulTableModel. The problem is, that not all my columns contain the same data type (seemingly the default type seems to be String), so I need to set the data type for all columns directly while creating the DefaultTableModel. How can this be don? I did not find a method to change the column class later on.
If I create my own "TableModelClass" that extends DefaultTableModel, how do I need to create a constructor that works something like this:
TableModelClass(data, columnNames, columnType)
columnType should be a vector containing the Class types like
String.class, Boolean.class etc.
ResultSetMetaData md = rs.getMetaData();
probably is info You expected. Call only once while openning, metadata is ok when zero rows is in query result too.
BTW I usually
build kind of "table metadata" like human readable column captions (Polish language).
be aware at null in some rows (You are ok)
I use traditionally Map< String,OBject > but vector is good to.
copy & paste from my real code, this sample is from web (Wicket) but data modelling is the same.
protected Map<String, Object> move_fields() {
Map<String, Object> rec = new HashMap<String, Object>();
// MathContext mc = new MathContext(2);
for (int i = 0; i < columns; i++) {
String key;
try {
key = md.getColumnName(i + 1).toLowerCase();
int type = md.getColumnType(i + 1);
Object o;
switch (type) {
case java.sql.Types.DOUBLE:
case java.sql.Types.DECIMAL:
case java.sql.Types.FLOAT:
case java.sql.Types.NUMERIC:
BigDecimal bd = rs.getBigDecimal(i + 1);
if (bd != null) {
// bd = bd.round(mc);
bd = bd.setScale(2, RoundingMode.HALF_EVEN);
}
o = bd;
break;
default:
o = rs.getObject(i + 1);
break;
}
rec.put(key, o);
} catch (SQLException e) {
e.printStackTrace();
}
}
for (Entry<String, DynamicField> v : virtuals.entrySet()) {
v.getValue().prepare(rs, record, _my_has_next);
Object o = v.getValue().getValue(rs, record, _my_has_next);
rec.put(v.getValue().getNameInTemplate(), o);
}
for (Entry<String, String> f: rest.entrySet()) {
String kolumna = f.getKey();
String prawo = f.getValue();
if(prawa.contains(prawo)){
int c=1;
}
else{
record.put(kolumna, "");
}
}
return rec;
}
This is a last resort. I'm studying development of Information Systems and even my teachers can't solve this... this is a nut for you to crack!!
This is the problem: My jTable in GUI gives me this:
This is what Microsoft Management Studio shows me:
As you can tell the jTable (GUI) has got 2 main problems:
The columnname "Name" does not contain any information. And it should? Why isn't it showing?
Since as you can tell, the table contains several columns, too many to even show. I therefore want to "add a restriction" that changes so that the jTable only shows the first 6 columns.
This is the code for the "creation of the table", in the DataAccessLayer:
private TableModel getResultSetAsDefaultTableModel(ResultSet rs) {
try {
String[] columnHeadings = new String[0];
Object[][] dataArray = new Object[0][0];
ResultSetMetaData md = rs.getMetaData();
int columnCount = md.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String columnName = md.getColumnName(i);
columnHeadings = Arrays.copyOf(columnHeadings, columnHeadings.length + 1);
columnHeadings[i - 1] = columnName;
}
int r = 0;
while (rs.next()) {
Object[] row = new Object[columnCount];
for (int i = 1; i <= columnCount; i++) {
row[i - 1] = rs.getObject(i);
}
dataArray = Arrays.copyOf(dataArray, dataArray.length + 1);
dataArray[r] = row;
r++;
}
DefaultTableModel dtm = new DefaultTableModel(dataArray, columnHeadings) {
public boolean isCellEditable(int row, int column) {
return false;
}
};
return dtm;
} catch (SQLException ex) {
Logger.getLogger(Dataaccesslayer.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
If you want me to show you the path of the code (frame, controller) just say so and I'll post it.
I would be so thankful if anyone can solve this...
Regards,
Christian
I think it is because in your for loop it should say i = 0; and not i = 1; since the first information (the name) is at index 0 right ?
In your case it could be enough to just leave the for-loop as it is and change this line to:row[i - 1] = rs.getObject(i-1);
To hide or show columns you could call setMin setMax and setPreferredWidth on your TableColumn.
Change your method like next, I think it helps you:
private TableModel getResultSetAsDefaultTableModel(ResultSet rs) {
try {
List<String> columnHeadings = new ArrayList<String>();
Object[][] dataArray = new Object[0][0];
ResultSetMetaData md = rs.getMetaData();
int columnCount = md.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
columnHeadings.add(md.getColumnName(i));
}
int r = 0;
while (rs.next()) {
Object[] row = new Object[columnCount];
for (int i = 1; i <= columnCount; i++) {
row[i-1] = rs.getObject(i);
}
dataArray = Arrays.copyOf(dataArray, dataArray.length + 1);
dataArray[r] = row;
r++;
}
DefaultTableModel dtm = new DefaultTableModel(dataArray,columnHeadings.toArray(new Object[columnHeadings.size()])) {
public boolean isCellEditable(int row, int column) {
return false;
}
};
return dtm;
} catch (SQLException ex) {
Logger.getLogger(Dataaccesslayer.class.getName()).log(Level.SEVERE,null, ex);
}
return null;
}
For showing not all columns use dtm.setColumnCount(2);. Here 2 is column count to show.
I am using the following to add retrieved values to the class. all values will be added to attributes of the class but I am using compisition ( have an object of class in the class) and it does not show anything on output.
class employee
{
....
private Address address = new Address();
.....
}
...
Employee emp = new Employee();
try {
ps = con.prepareStatement("select * from employee,address "
+ "WHERE employee.username = ? AND "
+ "employee.ADD_ID = address.ID");
ps.setString(1, username);
ResultSet r = ps.executeQuery();
if (r.next()) {
BeanProcessor bp = new BeanProcessor();
emp = bp.toBean(r,Employee.class);
System.out.println("blockkkk:"+emp.getAddress().getBlock());
//output of above line is blockkkk:null
}
con.close();
ps.close();
} catch (SQLException e) {
System.err.println(e.getMessage());
}
return emp;
Address class is as following:
public class Address {
.....
private String block;
....
public String getBlock() {
return block;
}
public void setBlock(String block) {
this.block = block;
}
....
}
The BeanProcessor.toBean works like this:
Convert a ResultSet row into a JavaBean. This implementation uses reflection and BeanInfo classes to match column names to bean property names. Properties are matched to columns based on several factors:
The class has a writable property with the same name as a column. The name comparison is case insensitive.
The column type can be converted to the property's set method parameter type with a ResultSet.get* method. If the conversion fails (ie. the property was an int and the column was a Timestamp) an SQLException is thrown.
Primitive bean properties are set to their defaults when SQL NULL is returned from the ResultSet. Numeric fields are set to 0 and booleans are set to false. Object bean properties are set to null when SQL NULL is returned. This is the same behavior as the ResultSet get* methods.
May be the address is not a writable property. Pls do check it.
public static Object copyFromResultSet(Class clazz, ResultSet resultSet)
{
ArrayList objectArrayList = new ArrayList(1);
try
{
Object object = clazz.newInstance();
objectArrayList.add(object);
copyFromResultSet(objectArrayList, resultSet);
}
catch (Exception e)
{
e.printStackTrace();
}
return objectArrayList.get(0);
}
then:
public static void copyFromResultSet(ArrayList<Object> objectArrayList, ResultSet resultSet)
{
ArrayList arrayList = null;
try
{
if (objectArrayList != null)
{
int objectArrayList_len = objectArrayList.size();
int objectArrayList_index = 0;
java.beans.BeanInfo toBeanInfo[] = new java.beans.BeanInfo[objectArrayList_len];
Vector<Method> objectMethodVector[] = new Vector[objectArrayList_len];
Vector<Type> objectTypeVector[] = new Vector[objectArrayList_len];
int totalMethod[] = new int[objectArrayList_len];
int[][] indexes = new int[objectArrayList_len][];
for (objectArrayList_index = 0; objectArrayList_index < objectArrayList_len; objectArrayList_index++)
{
toBeanInfo[objectArrayList_index] = java.beans.Introspector.getBeanInfo(objectArrayList.get(objectArrayList_index).getClass());
}
if (objectArrayList_len > 0 && resultSet != null)
{
Method method = null;
Type type[] = null;
int cols = 0;
String colName = null;
for (objectArrayList_index = 0; objectArrayList_index < objectArrayList_len; objectArrayList_index++)
{
//toBeanInfo[objectArrayList_index]=java.beans.Introspector.getBeanInfo(objectArrayList.get(objectArrayList_index).getClass());
java.beans.PropertyDescriptor toPropertyDescriptor[] = toBeanInfo[objectArrayList_index].getPropertyDescriptors();
int toPropertyDescriptor_length = toPropertyDescriptor.length;
method = null;
type = null;
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
cols = resultSetMetaData.getColumnCount();
colName = null;
Vector<Method> methodVector = new Vector(cols);
Vector<Type> typeVector = new Vector(cols);
indexes[objectArrayList_index] = new int[cols];
totalMethod[objectArrayList_index] = -1;
for (int i = 1; i <= cols; i++)
{
colName = resultSetMetaData.getColumnName(i);
for (int j = 0; j < toPropertyDescriptor_length; j++)
{
if (toPropertyDescriptor[j].getName().equalsIgnoreCase(colName))
{
totalMethod[objectArrayList_index]++;
method = toPropertyDescriptor[j].getWriteMethod();
type = method.getGenericParameterTypes();
methodVector.add(method);
typeVector.add(type[0]);
indexes[objectArrayList_index][totalMethod[objectArrayList_index]] = i;
break;
}
}
}
objectMethodVector[objectArrayList_index] = (methodVector);
objectTypeVector[objectArrayList_index] = (typeVector);
}
if (resultSet.next())
{
arrayList = new ArrayList();
for (objectArrayList_index = 0; objectArrayList_index < objectArrayList_len; objectArrayList_index++)
{
for (int i = 0; i <= totalMethod[objectArrayList_index]; i++)
{
//System.out.println(objectMethodVector[objectArrayList_index].get(i));
objectMethodVector[objectArrayList_index].get(i).invoke(objectArrayList.get(objectArrayList_index), getObject(indexes[objectArrayList_index][i], objectTypeVector[objectArrayList_index].get(i), resultSet));
}
arrayList.add(objectArrayList.get(objectArrayList_index));
}
}
while (resultSet.next())
{
for (objectArrayList_index = 0; objectArrayList_index < objectArrayList_len; objectArrayList_index++)
{
for (int i = 0; i <= totalMethod[objectArrayList_index]; i++)
{
objectMethodVector[objectArrayList_index].get(i).invoke(objectArrayList.get(objectArrayList_index), getObject(indexes[objectArrayList_index][i], objectTypeVector[objectArrayList_index].get(i), resultSet));
}
arrayList.add(objectArrayList.get(objectArrayList_index));
}
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
just copy paste this code call method copyFromResultSet(class, ResultSet )
pass two perameters first is class name and second is resultset.
i am sure this is working properlly
I'm using a ResultSet in Java, and am not sure how to properly close it. I'm considering using the ResultSet to construct a HashMap and then closing the ResultSet after that. Is this HashMap technique efficient, or are there more efficient ways of handling this situation? I need both keys and values, so using a HashMap seemed like a logical choice.
If using a HashMap is the most efficient method, how do I construct and use the HashMap in my code?
Here's what I've tried:
public HashMap resultSetToHashMap(ResultSet rs) throws SQLException {
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
HashMap row = new HashMap();
while (rs.next()) {
for (int i = 1; i <= columns; i++) {
row.put(md.getColumnName(i), rs.getObject(i));
}
}
return row;
}
Iterate over the ResultSet
Create a new Object for each row, to store the fields you need
Add this new object to ArrayList or Hashmap or whatever you fancy
Close the ResultSet, Statement and the DB connection
Done
EDIT: now that you have posted code, I have made a few changes to it.
public List resultSetToArrayList(ResultSet rs) throws SQLException{
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
ArrayList list = new ArrayList(50);
while (rs.next()){
HashMap row = new HashMap(columns);
for(int i=1; i<=columns; ++i){
row.put(md.getColumnName(i),rs.getObject(i));
}
list.add(row);
}
return list;
}
I just cleaned up RHT's answer to eliminate some warnings and thought I would share. Eclipse did most of the work:
public List<HashMap<String,Object>> convertResultSetToList(ResultSet rs) throws SQLException {
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
List<HashMap<String,Object>> list = new ArrayList<HashMap<String,Object>>();
while (rs.next()) {
HashMap<String,Object> row = new HashMap<String, Object>(columns);
for(int i=1; i<=columns; ++i) {
row.put(md.getColumnName(i),rs.getObject(i));
}
list.add(row);
}
return list;
}
RHT pretty much has it. Or you could use a RowSetDynaClass and let someone else do all the work :)
this is my alternative solution, instead of a List of Map, i'm using a Map of List.
Tested on tables of 5000 elements, on a remote db, times are around 350ms for eiter method.
private Map<String, List<Object>> resultSetToArrayList(ResultSet rs) throws SQLException {
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
Map<String, List<Object>> map = new HashMap<>(columns);
for (int i = 1; i <= columns; ++i) {
map.put(md.getColumnName(i), new ArrayList<>());
}
while (rs.next()) {
for (int i = 1; i <= columns; ++i) {
map.get(md.getColumnName(i)).add(rs.getObject(i));
}
}
return map;
}
A couple of things to enhance the other answers. First, you should never return a HashMap, which is a specific implementation. Return instead a plain old java.util.Map. But that's actually not right for this example, anyway. Your code only returns the last row of the ResultSet as a (Hash)Map. You instead want to return a List<Map<String,Object>>. Think about how you should modify your code to do that. (Or you could take Dave Newton's suggestion).
i improved the solutions of RHTs/Brad Ms and of Lestos answer.
i extended both solutions in leaving the state there, where it was found.
So i save the current ResultSet position and restore it after i created the maps.
The rs is the ResultSet, its a field variable and so in my solutions-snippets not visible.
I replaced the specific Map in Brad Ms solution to the gerneric Map.
public List<Map<String, Object>> resultAsListMap() throws SQLException
{
var md = rs.getMetaData();
var columns = md.getColumnCount();
var list = new ArrayList<Map<String, Object>>();
var currRowIndex = rs.getRow();
rs.beforeFirst();
while (rs.next())
{
HashMap<String, Object> row = new HashMap<String, Object>(columns);
for (int i = 1; i <= columns; ++i)
{
row.put(md.getColumnName(i), rs.getObject(i));
}
list.add(row);
}
rs.absolute(currRowIndex);
return list;
}
In Lestos solution, i optimized the code. In his code he have to lookup the Maps each iteration of that for-loop. I reduced that to only one array-acces each for-loop iteration. So the program must not seach each iteration step for that string-key.
public Map<String, List<Object>> resultAsMapList() throws SQLException
{
var md = rs.getMetaData();
var columns = md.getColumnCount();
var tmp = new ArrayList[columns];
var map = new HashMap<String, List<Object>>(columns);
var currRowIndex = rs.getRow();
rs.beforeFirst();
for (int i = 1; i <= columns; ++i)
{
tmp[i - 1] = new ArrayList<>();
map.put(md.getColumnName(i), tmp[i - 1]);
}
while (rs.next())
{
for (int i = 1; i <= columns; ++i)
{
tmp[i - 1].add(rs.getObject(i));
}
}
rs.absolute(currRowIndex);
return map;
}
Here is the code little modified that i got it from google -
List data_table = new ArrayList<>();
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection(conn_url, user_id, password);
Statement stmt = con.createStatement();
System.out.println("query_string: "+query_string);
ResultSet rs = stmt.executeQuery(query_string);
ResultSetMetaData rsmd = rs.getMetaData();
int row_count = 0;
while (rs.next()) {
HashMap<String, String> data_map = new HashMap<>();
if (row_count == 240001) {
break;
}
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
data_map.put(rsmd.getColumnName(i), rs.getString(i));
}
data_table.add(data_map);
row_count = row_count + 1;
}
rs.close();
stmt.close();
con.close();
public static List<HashMap<Object, Object>> GetListOfDataFromResultSet(ResultSet rs) throws SQLException {
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount();
String[] columnName = new String[count];
List<HashMap<Object,Object>> lst=new ArrayList<>();
while(rs.next()) {
HashMap<Object,Object> map=new HashMap<>();
for (int i = 1; i <= count; i++){
columnName[i-1] = metaData.getColumnLabel(i);
map.put(columnName[i-1], rs.getObject(i));
}
lst.add(map);
}
return lst;
}