I would like to create DefaultTableModel from ResultSet. To do that, I need Object[][].
For that, I have to specify the size of the object before I iterate through the table: I go to the rs.last(), then rs.getRow(), then rs.beforeFirst();
After that, the rs.next() does not executes in the while cycle.
What am I doing wrong?
public static DefaultTableModel buildTableModel(ResultSet _resultSet) {
ResultSetMetaData metaData;
Object[] columnNames = null;
Object[][] tableData = null;
int columnCount;
int currentRowNumber = 0;
try {
metaData = _resultSet.getMetaData();
columnCount = metaData.getColumnCount();
columnNames = new Object[columnCount];
_resultSet.last();
tableData = new Object[_resultSet.getRow()][columnCount];
_resultSet.beforeFirst();
for (int currentColumn = 0; currentColumn <= columnCount; currentColumn++) {
columnNames[currentColumn] = metaData.getColumnName(currentColumn + 1);
}
while (_resultSet.next()) {
for (int columnIndex = 0; columnIndex <= columnCount; columnIndex++) {
tableData[currentRowNumber][columnIndex] = _resultSet.getObject(columnIndex + 1);
}
currentRowNumber++;
}
} catch (SQLException ex) {
System.out.println("bad");
}
return new DefaultTableModel(tableData, columnNames);
}
Probably your ResultSet is not scroll insensitive, that is, it can only be traversed forward.
See the documentation here:
[...] A default ResultSet object is not updatable and has a cursor that moves forward only. Thus, you can iterate through it only once and only from the first row to the last row. [...]
To create a bi-directional one, do something like:
Connection conn = DriverManager.getConnection(...);
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ...);
ResultSet rset = stmt.executeQuery(sql);
At first you need to print column name from ResultSetMetaData. Than you apply _resultSet.last(); and _resultSet.beforeFirst();. This way it has been working my machine.
public static DefaultTableModel buildTableModel(ResultSet _resultSet) {
ResultSetMetaData metaData;
Object[] columnNames = null;
Object[][] tableData = null;
int columnCount;
int currentRowNumber = 0;
try {
metaData = _resultSet.getMetaData();
columnCount = metaData.getColumnCount();
columnNames = new Object[columnCount];
// Print column here.
for (int currentColumn = 0; currentColumn <= columnCount; currentColumn++) {
columnNames[currentColumn] = metaData.getColumnName(currentColumn + 1);
}
tableData = new Object[_resultSet.getRow()][columnCount];
//Here point resultSet cursor to last and beforeFirst.
_resultSet.last();
_resultSet.beforeFirst();
// After swaping the above part. Now it will enter on while loop.
while (_resultSet.next()) {
for (int columnIndex = 0; columnIndex <= columnCount; columnIndex++) {
tableData[currentRowNumber][columnIndex] = _resultSet.getObject(columnIndex + 1);
}
currentRowNumber++;
}
} catch (SQLException ex) {
System.out.println("bad");
}
return new DefaultTableModel(tableData, columnNames);
}
Related
I seem to be have a problem when trying to get the coulmn count from a resultset's metadata. THe error is Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: SQLite JDBC: inconsistent internal state.
THe idea is to use this table model to populate a JTable with the result from the database query. However when I do I get the above error.
The relevant code is:
public DefaultTableModel buildFlightModel()
throws SQLException {
query="SELECT Airline.AirlineName, Flight.FlightID, Flight.Location, Flight.Destination, Flight.ArriveTime, Flight.LeaveTime FROM Flight INNER JOIN Airline ON Airline.AirlineID=Flight.AirlineID;";
try {
Class.forName("org.sqlite.JDBC");
c = DriverManager.getConnection("jdbc:sqlite:coursework.db");
stmt = c.createStatement();
rs=stmt.executeQuery(query);
while(rs.next()){
//System.out.println(s);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ResultSetMetaData metaData = rs.getMetaData();
// names of columns
Vector<String> columnNames = new Vector<String>();
int columnCount = metaData.getColumnCount();
for (int column = 1; column <= columnCount; column++) {
columnNames.add(metaData.getColumnName(column));
}
// data of the 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++) {
vector.add(rs.getObject(columnIndex));
}
data.add(vector);
}
return new DefaultTableModel(data, columnNames);
}
Any thoughts/ideas/help would be deeply appreciated. Thank you.
This exception is thrown when ResultSet.isclose() == true. Try to create a Clone of the MetaData before starting the Read-Loop.
i already searched the whole web but I can't find a solution, so i decided to ask here.
Following problem: I am using those 2 methods to populate a JTable with a DefaultTableModel, the ResultSet shows the right amount of data entries (i already searched it with System.out.println) but the JTable always misses the first row
I am using a method to get a ResultSet like this:
public static JTable DBCFillBTableAuftraege() {
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
JTable table = null;
try {
con = DriverManager.getConnection(host, uName, uPass);
stmt = con.createStatement( );
rs = stmt.executeQuery("SELECT a.auftrags_nr, k.firma, a.auftragsdatum, a.lieferdatum, a.rechnungsbetrag, k.name, k.strasse, k.plz, k.ort from auftrag a join kunde k on k.kunden_nr = a.kunden_nr ");
while (rs.next()) {
table = new JTable(tableModel(rs));
return table;
}
} catch (SQLException e) {
System.out.println(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return table;
}
Which then calls this method:
public static DefaultTableModel TableModel(ResultSet rs)
throws SQLException {
ResultSetMetaData metaData = rs.getMetaData();
System.out.println(rs);
// names of columns
Vector<String> columnNames = new Vector<String>();
int columnCount = metaData.getColumnCount();
for (int column = 1; column <= columnCount; column++) {
columnNames.add(metaData.getColumnName(column));
}
// data of the 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++) {
vector.add(rs.getObject(columnIndex));
}
data.add(vector);
}
return new DefaultTableModel(data, columnNames);
}
In my main:
TableAuftrag = DBCFillBTableAuftraege();
scpaneBestell.setViewportView(TableAuftrag);
It works fine, it is showing me my column headers and the data, except one problem:
It is always missing the first row and starts with the second one
Your problem starts here...
// Move to first row...
while (rs.next()) {
table = new JTable(tableModel(rs));
return table;
}
and manifests
// Move to second row and beyond...
while (rs.next()) {
Vector<Object> vector = new Vector<Object>();
for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
vector.add(rs.getObject(columnIndex));
}
data.add(vector);
}
Basically, in the first while (rs.next()), you move to the first row, but in the second while (rs.next()) you move to the second row, without handling the first...
It might be better to simply pass the ResultSet directly to the TableModel.
Convention would also suggest that you probably should not need to create a new JTable, but instead, just create a new TableModel and apply to a pre-existing table
while (rs.next()) {
table = new JTable(tableModel(rs));
return table;
}
You're consuming the first row of the result set here, and then call tableModel(), which consumes the other rows. The while loop is useless. Just do
table = new JTable(tableModel(rs));
return table;
I have a problem in updating my single jtable from Microsoft Access Database.
I do not have any error messages. I tried out the Query for the database using like, but my jtable does not populate in relation to the data stored in the database.
public TableModel setAuthorSearchEjournalTableValues(){
String eJournalAuthor = jTextField30.getText();
ResultSet tableData = DCE.searchEjournalbyAuthor(eJournalAuthor);
try {
ResultSetMetaData md = tableData.getMetaData();
int columnCount = md.getColumnCount();
Vector columns = new Vector(columnCount);
for (int i = 1; i <= columnCount; i++) {
columns.add(md.getColumnName(i));
}
Vector data = new Vector();
Vector row;
while (tableData.next()) {
row = new Vector(columnCount);
for (int i = 1; i <= columnCount; i++) {
row.addElement( tableData.getString(i) );
}
data.add(row);
}
DefaultTableModel tableModel = new DefaultTableModel(data, columns);
return tableModel;
//Debugging
} catch (SQLException ex) {
ex.printStackTrace();
}
return null;
}`
And my result retrieving query is here
public ResultSet searchEjournalbyAuthor(String author){
conn = Connect();
try{
String myQuery = "select AuthorDetails,Year,Titleofarticle,Journaltitle,volume,pagenumbers,URL,AccessedDate from Ejournalcitation where AuthorDetails = '"+author+"'";
pst = conn.prepareStatement(myQuery);
rs = pst.executeQuery();
return rs;
}catch(SQLException ex){
ex.printStackTrace();
}
return null;
}
with the code to display as
private void jTextField30KeyReleased(java.awt.event.KeyEvent evt) {
// TODO add your handling code here:
if(jComboBox1.getSelectedIndex()==0&&jComboBox2.getSelectedIndex()==0){//BookTitle
jTable1.setModel(setTitleSearchBookTableValues());
}
else if(jComboBox1.getSelectedIndex()==0&&jComboBox2.getSelectedIndex()==1){//BookAuthor
jTable1.setModel(setAuthorSearchBookTableValues());
}
else if(jComboBox1.getSelectedIndex()==1&&jComboBox2.getSelectedIndex()==0){//WebSiteTitle
jTable1.setModel(setTitleSearchWebSiteTableValues());
}
else if(jComboBox1.getSelectedIndex()==1&&jComboBox2.getSelectedIndex()==1){//WebSiteAuthor
jTable1.setModel(setAuthorSearchWebSiteTableValues());
}
else if(jComboBox1.getSelectedIndex()==2&&jComboBox2.getSelectedIndex()==0){//Ejournaltitle
jTable1.setModel(setTitleSearchEjournalTableValues());
}
else if(jComboBox1.getSelectedIndex()==3&&jComboBox2.getSelectedIndex()==1){//EjournalAuthor
jTable1.setModel(setAuthorSearchEjournalTableValues());
}
else{
JOptionPane.showMessageDialog(null, "Please enter a value and select the type of search");
}
}
Help me out!! Thanks in advance
you must include
DefaultTableModel tableModel = (DefaultTableModel) jTable1.getModel();
tableModel.fireTableDataChanged();
with the corrected query
String myQuery = "select AuthorDetails,Year,Titleofarticle,Journaltitle,volume,pagenumbers,URL,AccessedDate from Ejournalcitation where AuthorDetails like '%"+author+"%'";
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.
This is the code for the "creation" of the table I have in my 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;
}
**This results in some complications, since one of my tables has 50 different columns and therefore you can't read the columnnames or what is in the cell.
The problem is that the table's values are determined by the metadata...
I want to limit the columns that are showed to a specific number (5) for all tables.
How do I do it?**
Kind regards,
Chris
you can remove tables if you want to...
int amountColumns = table.getColumnModel().getColumnCount(); //count columns
TableColumn c6 = table.getColumnModel().getColumn(6); //identif a random column
table.getColumnModel().removeColumn(c6); //remove this column
i hope that helped...
I would not remove them but change their size to 0.
int amountColumns = table.getColumnModel().getColumnCount(); //count columns
TableColumn c6 = table.getColumnModel().getColumn(6); //identif a random column
table.getColumnModel().setMin(0);
table.getColumnModel().setMax(0);
table.getColumnModel().setPreferredWidth(0);
Like i answered you in your other thread...