I am thinking about the design of the method that will enable the user to potentially pass a list of integers that indicate the columns that the user wishes to retrieve from the database.
I do not want to hardcode multiple methods that esentially do the same thing, i.e. show the user different columns but from the same table.
here is the code from Oracle tutorials on retrieving the values using JDBC:
public static void viewTable(Connection con, String dbName)
throws SQLException {
Statement stmt = null;
String query =
"select COF_NAME, SUP_ID, PRICE, " +
"SALES, TOTAL " +
"from " + dbName + ".COFFEES";
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
int supplierID = rs.getInt("SUP_ID");
float price = rs.getFloat("PRICE");
int sales = rs.getInt("SALES");
int total = rs.getInt("TOTAL");
System.out.println(coffeeName + "\t" + supplierID +
"\t" + price + "\t" + sales +
"\t" + total);
}
} catch (SQLException e ) {
JDBCTutorialUtilities.printSQLException(e);
} finally {
if (stmt != null) { stmt.close(); }
}
}
So the query is not a problem, the column names can be concatenated, depending on which columns the user wants to see. The issue is in the try block. How does one .get the correct format from the result set? Or should I simply use the String for every column? Or should I hardcode all the table columns (rs.get depending on what data type the column is) and then in println return only the columns that the user wishes to see (actually how would I do that)? Well, I guess you understand my issue.
You can retrieve all the data from the particular table and use it to populate a collection of the appropriate object. And then based on the user's choice, you could just print out the appropriate columns.
Assuming you know how to create the collection of the appropriate object, I will explain how you can do the next step.
You can display a message to the user asking him to enter the columns he wishes to see. Like, Enter 1 to see the coffee name, 2 to see the supplier id, 3 to see the price etc. and 0 to view the data.
So you basically keep reading the int's until the user enters a 0. Once he enters a zero, display the requested values.
Related
I am building a simple program for a library database system in Java where patrons can borrow and return books. The database has 4 tables: Book, Author, Patrons, and AuthorIds. I'm using the SQL statement below to retrieve 1 row of data that includes everything plus a column that counts how many books the patron has already borrowed. The problem is that the program never goes into the while(res.next()) loop and I think it's because the result set is empty. The test print doesn't get printed and membID doesn't get changed to the MemberID of the patron.
But when I try that same SQL statement on db browser on the same database it returns 1 row as expected with the BooksBorrowed column. All of my other ResultSet while loops have worked and returned rows with other SQL statements, it's just this one that doesn't and I don't know why.
public void borrowBooks(String fName, String lName, Scanner input) throws SQLException {
//first find out how many books the user has already borrowed
int booksBorrowed = 0;
int membID = 1; //this will be used for later
sql = "select *, Count(MemberID) AS BooksBorrowed\r\n" +
"FROM Book\r\n" +
" JOIN AuthorIds USING (BookID)\r\n" +
" JOIN Author USING (AuthorID)\r\n" +
" JOIN Patron USING (MemberID)\r\n" +
"WHERE PatronFirstName LIKE ? AND PatronLastName LIKE ?\r\n" +
"GROUP BY MemberID\r\n" +
"ORDER BY BookID ASC";
PreparedStatement stmt = connection.prepareStatement( sql );
stmt.setString(1, fName);
stmt.setString(2, lName);
ResultSet res = stmt.executeQuery();
while(res.next()) {
booksBorrowed = res.getInt("BooksBorrowed");
System.out.println(res.getInt("MemberID"));
System.out.println("Test");
membID = res.getInt("MemberID");
}
if(booksBorrowed >= 2) {
System.out.println("You have already borrowed the maximum amount of 2 books. Return books to borrow more");
}
I figured it out and it was that I should have gotten the memberID in a separate query because I was trying to change it to the corresponding patron in the same query as I was trying to get the number of books borrowed. The problem was that if the patron didn't have any books borrowed, then the result set would be empty and the memberID wouldn't change from what it was temporarily initialized as. This memberID was later inserted into the table for when a book was borrowed so it would be the temporary stand in each time and not the actual memberID of the patron, so the patron would have no books under their name as borrowed.
So I have a database that is made like this
{MATERIAL NAME;QUANTITY}
I also have a JTable in Java that uploads the info from the database (SQLite). As I edit a cell in the table, it automatically updates the database in this way:
//table listener
public void tableChanged(TableModelEvent e) {
//gets row and column if the table is edited
int row = e.getFirstRow();
int column = e.getColumn();
//change in sqlite
if (column == 1) {
int value = Integer.parseInt(table.getModel().getValueAt(row, column).toString());
String materialId = table.getModel().getValueAt(row, column-1).toString();
try (Connection c = DriverManager.getConnection("jdbc:sqlite:database.db"); Statement statement = c.createStatement()) {
String sql = "UPDATE MATERIALS set QUANTITY = " + value + " where MATERIAL='" + materialId +"';";
statement.executeUpdate(sql);
statement.close();
c.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
else if (column == 0) {
int value = Integer.parseInt(table.getModel().getValueAt(row, column+1).toString());
String materialId = table.getModel().getValueAt(row, column).toString();
try (Connection c = DriverManager.getConnection("jdbc:sqlite:database.db"); Statement statement = c.createStatement()) {
String sql = "UPDATE MATERIALS set MATERIAL = " + materialId + " where MATERIAL='" + materialId +"';";
statement.executeUpdate(sql);
statement.close();
c.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
It's okay when the quantity is updated. However, once the material name is updated, I don't know how I am supposed to update it in the database.
String sql = "UPDATE MATERIALS set MATERIAL = " + materialId + " where MATERIAL='" + materialId +"';";
Maybe there is a way to save a previous value of that value? I can not use the quantity of materials as they might be repeated.
I would like to avoid adding IDs to the objects if possible.
This statement:
String sql = "UPDATE MATERIALS set MATERIAL = " + materialId + " where MATERIAL='" + materialId +"';"
Has two (three) problems.
The 'old' value and the 'new' value are the same. You have a logical problem.
WHERE part is concatenated like for string type, but SET part is not
concatenation is evil. The Correct way to do this is
String sql = "UPDATE MATERIALS set MATERIAL = ? where MATERIAL= ?";
PreparedStatement prepstmt = conn.prepareStatement(sql);
prepstmt .setString(1, newMatewrial);
prepstmt .setString(2, oldMaterial);
prepstmt .executeUpdate();
Logical problem must be resolved in your conception.
It Seems the main problem is in basically not using the ID . Every row in relational database should have stable primary key (ID like You say). Name isn't primary key, because can be changed.
WHERE part should use ID and not name.
EDIT: in my opinion good JTable model is one way to solve your problem.
Maybe automagic default table model is too poor. Class implementing Row should have one more column (ID) which can(or not) be invisible.
My English isn't too fluent, cannot teach relational database and Swing in SO post.
The second, small snippet of code doesn't show your application conception.
Read in google about custom JTable model.
Very basic example:
http://www.java2s.com/Code/Java/Swing-JFC/TablewithacustomTableModel.htm
Okay so it seems that I found the solution to the problem
JTable: Detect cell data change
However, this requires implementing another class into the project and using it. The answer for the SQL statement still stays the same.
I need to write a file by reading an xml, containing format information and values to be fetched from database. I am working on large number of records(200,000).
I have tried keeping all the data in memory but got out of memory error.
I have tried hitting database again and again but then I got performance issue. As queries being hit again and again decreases performance.
Steps involved for the process:
hitting db to get all records for which file is to be created
reading xml file using Jaxb
creating map of all the data obtained from step 1.
iterating over map obtained from step1
deriving what data need to be displayed from format object created
in step 2
appending result in a string for each record and then writing same
into file
Though, finally I resolved this by reading a predefined count of data once and write file for this and then work on next bunch. But I have not followed any design pattern for this.
Is there a design pattern that uses minimum memory and let me write file efficiently?
The design pattern is called Pagination (using a cursor). When you send a query to Oracle DB for example, the default number of results in the resultset returned is 50. Only when you ask the resultset to get next() it'll return the next 50 results. That's how most DBs work and designed to be efficient for such a pattern (see this code example):
public static void viewTable(Connection con, String dbName)
throws SQLException {
Statement stmt = null;
String query =
"select COF_NAME, SUP_ID, PRICE, " +
"SALES, TOTAL " +
"from " + dbName + ".COFFEES";
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
int supplierID = rs.getInt("SUP_ID");
float price = rs.getFloat("PRICE");
int sales = rs.getInt("SALES");
int total = rs.getInt("TOTAL");
System.out.println(coffeeName + "\t" + supplierID +
"\t" + price + "\t" + sales +
"\t" + total);
}
} catch (SQLException e ) {
JDBCTutorialUtilities.printSQLException(e);
} finally {
if (stmt != null) { stmt.close(); }
}
}
So, you can open the file, and write every "page" of results that you're getting, ask for the next page etc. Once you're done - close the file.
If you are writing to XML, I suggest writing out each record as you read it in. This way you only need enough memory for one record at a time and it doesn't matter how many records you have.
e.g.
Statement stmt = null;
String query =
"select COF_NAME, SUP_ID, PRICE, " +
"SALES, TOTAL " +
"from " + dbName + ".COFFEES";
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
xmlFile.println("<coffee>\n" +
"<coffeename>" + rs.getString("COF_NAME") + "</coffeename>\n" +
"<supId>" + rs.getInt("SUP_ID")+ "</supId>\n" +
"<price>" + rs.getFloat("PRICE") + "</price>\n" +
"<sales>" + rs.getInt("SALES") + "</sales>\n" +
"<total>" + rs.getInt("TOTAL") + "</total>\n" +
"</coffee>");
}
} catch (SQLException e ) {
JDBCTutorialUtilities.printSQLException(e);
} finally {
if (stmt != null) { stmt.close(); }
}
You may need to escape out strings in case they contain special characters.
I'm trying to access what the rowSet variable has returned i.e. it is retreving everything from properties where two conditions are met, BUT:
JdbcRowSetImpl rowSet = new JdbcRowSetImpl();
int price = 300000;
rowSet.setUrl("jdbc:mysql://localhost:3306/litrealty");
rowSet.setUsername("root");
rowSet.setPassword("");
rowSet.setCommand("SELECT * FROM properties WHERE city = ? AND price < ?");
rowSet.setString(1, l);
rowSet.setInt(2, price);
rowSet.execute();
since this piece of code is retreving these informations from the database how can I access it and i.e. put into an array so I can scroll through it then via next/previous buttons?
you can use while loop and iterate on your rowset and get the data
it would look something like this:
//Creating and Executing RowSet
JdbcRowSet rowSet = RowSetProvider.newFactory().createJdbcRowSet();
rowSet.setUrl("jdbc:mysql://localhost:3306/litrealty");
rowSet.setUsername("root");
rowSet.setPassword("password");
rowSet.setCommand("select Id, Name, Salary from employee");
rowSet.execute();
while (rowSet.next()) {
System.out.println("Id: " + rowSet.getString(1));
System.out.println("Name: " + rowSet.getString(2));
System.out.println("Salary: " + rowSet.getString(3));
}
Instead i would suggest you to use PreparedStatement to fetch data base from database
I have to add two queries to a table model so that it shows up on the table. It is a program doing prediction on soccer (EPL to be precise) and I need to display ALL results for the team when they are playing both home, and away. the first query is to get all the games where they play home, the second query is when they play away. Here is the code:
public void showResultsTotalTeam(){
deleteAllRows(dTableModel); // deleta all rows in the table
try {
conn = DriverManager.getConnection(connection.conn_url, connection.conn_user, connection.conn_pass);// connect to database server
Statement sqlState = conn.createStatement();// create statement for sql
String selectStuff = "SELECT games_team1, games_team2, games_winner, games_draw, games_team1_score, games_team2_score, games_month, games_day FROM games WHERE games_team1 = '" + cbxTeam1.getSelectedItem() + "'";// ststement for MySQL
rows = sqlState.executeQuery(selectStuff); // execute statement
String selectStuff2 = "SELECT games_team1, games_team2, games_winner, games_draw, games_team1_score, games_team2_score, games_month, games_day FROM games WHERE games_team2 = '" + cbxTeam1.getSelectedItem() + "'";// ststement for MySQL
rows2 = sqlState.executeQuery(selectStuff); // execute statement
Object[] tempRow;// create object array to store queried results
Object[] tempRow2;
while(rows.next()){ // while there are still values to be seen to
tempRow = new Object[]{rows.getString(1), rows.getString(2), rows.getString(3), rows.getString(4), rows.getString(5), rows.getString(6), rows.getString(7), rows.getString(8)};// add data to array
tempRow2 = new Object[]{rows2.getString(1), rows2.getString(2), rows2.getString(3), rows2.getString(4), rows2.getString(5), rows2.getString(6), rows2.getString(7), rows2.getString(8)};
dTableModel.addRow(tempRow); // add array to table model
dTableModel.addRow(tempRow2);
}
} catch (SQLException ex) {
// TODO Auto-generated catch block
System.out.println(ex.getMessage());
}
}
Now this code does not work and nothing shows up at all.
Please help? Any advice would be great.
You haven't loaded thr driver class
Class.forName("Driver Class Name");
And you haven't closed anything. Connecton & ResultSet
Unless the number of rows == number of rows2 then you may encounter trouble when you are iterating through rows.next
Also suggest you iterate do you code in two distinct blocks i.e one for rows and one for rows2
Edit
This could also be done with one query
SELECT games_team1, games_team2, games_winner, games_draw, games_team1_score,
games_team2_score, games_month, games_day FROM games
WHERE games_team1 = '" + cbxTeam1.getSelectedItem() + "' "
or games_team2 = '" + cbxTeam1.getSelectedItem() + "' "