I'm a java beginner and struggle with two problems.
1) The SQL Exception: no such column 'Ofen'
This is my Code and I want to get specific data from a SQLite Database called "kleintest.db" with 2 tables "maindata" and "Zahlwertuntertable". maindata contains the 'Ofen' entry as TEXT. The ResultSet rs should generally take all Data from maindata and the ResultSet rs2 should take the weight from Zahlwertuntertable. But running the programm now shows the mentioned error.
public static void readDB() {
try {
Statement stmt = connection.createStatement();
//ResultSet rs = stmt.executeQuery("SELECT * FROM Gewichtsabnahme;");
ResultSet rs = stmt.executeQuery("SELECT * FROM maindata;");
ResultSet rs2 = stmt.executeQuery("SELECT * FROM Zahlwertuntertable;");
while (rs.next()) {
System.out.println("Ofen = " + rs.getString("Ofen"));
System.out.println("Platznummer = " + rs.getInt("Zahlwert"));
System.out.println("Startdatum = " + rs.getString("Startdatum"));
LocalDate heute = LocalDate.now();
String Datum = rs.getString("Startdatum");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
LocalDate Wägetag = LocalDate.parse(Datum, formatter);
Period DiffTag = Period.between(heute, Wägetag);
System.out.format("Tage = " + DiffTag.getDays() + "\n"); //
System.out.println("Gewicht = " + rs2.getInt("Startgewicht"));
}
rs.close();
rs2.close();
connection.close();
} catch (SQLException e) {
System.err.println("Zugriff auf DB nicht möglich.");
e.printStackTrace();
}
}
The table maindata contains the following items:
Laufnummer Ofen Zahlwert Startdatum
But Laufnummer is just a primary key and should not be retrieved.
2) Next Question is the thing with the Period function. This worked well but as a printed result I'll get P 1D or P 1M 2D what looks slightly confusing. I like to print just the simple amount of days like 45 or 45D and added the getDays() to my DiffTag. Now my result is -1 what makes no sense at all. What's wrong here?
Period DiffTag = Period.between(heute, Wägetag);
System.out.format("Tage = " + DiffTag.getDays() + "\n");
Thanks for suggestions and links I may have missed. But everything I looked so far didn't point out my specific questions.
You can only have one result set open at a time for a Statement object so when you execute the second query agains "Zahlwertuntertable" the first one gets closed.
So either add another statement or handle one query at a time.
Also, right now it looks strange that you call rs.next() but never rs2.next()
Related
I have a strange problem. I have a database and I want to change the values of a column. The values are safed in an Arraylist (timelist).
In order to write the values in the right row, I have a second Arrylist (namelist). So I want to read the first row in my Database, than I check the namelist and find the name. Than i take the matching value out of the timelist and write it into the database into the column "follows_date" in the row, matching to the name.
And than I read the next row of the Database, until there are no more entries.
So the strange thing is, if I change nothing in the database, the while(rs.next()) part works.
For example:
ResultSet rs = statement.executeQuery("SELECT username FROM users");
while(rs.next()){
// read the result set
String name = rs.getString("username");
System.out.println("username = " + name); //liest die namen
}
}
This would print me every name after name. But when I change the table, the while loop ends after that. (no error, the program just finishes)
ResultSet rs = statement.executeQuery("SELECT username FROM users");
while(rs.next()){
// read the result set
String name = rs.getString("username");
System.out.println("username = " + name); //writes the name
//look, if name is in Arraylist "namelist"). if yes, than write the matching date from "timelist" into the database.
if (namelist.contains(name)){
System.out.println("name found: "+ name);
int listIndizi = namelist.indexOf(name); //get index
Long indiziDatum = (long) timelist.get(listIndizi); //get date from same Index
System.out.println(indiziDatum); // print date so i can see it is correct (which it is)
statement.executeUpdate("UPDATE users SET follows_date ="+ indiziDatum +" WHERE username = '"+name+"'"); //updates the follows_date column
}
}
Everything works fine, except that now, the while loop doesn't continues after the first passage, but ends.
The resultSet of a statement is closed and will not return further results if you execute another statement. Create a new separate statement object for the update and everything should work as excepted.
Statement statement1 = connection.createStatement();
Statement statement2 = connection.createStatement();
ResultSet resultSet1 = statement1.executeQuery("SELECT username FROM users");
while(resultSet1.next()){
...
statement2.executeUpdate("UPDATE users ..."));
}
As to Why it happens:
Here is the explanation from the official documentation:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
Alternative Approach:
From your sample, it seems you are trying to update the "same" row in your resultSet, you should consider using an Updatable ResultSet.
Sample code from the official documentation:
public void modifyPrices(float percentage) throws SQLException {
Statement stmt = null;
try {
stmt = con.createStatement();
stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet uprs = stmt.executeQuery(
"SELECT * FROM " + dbName + ".COFFEES");
while (uprs.next()) {
float f = uprs.getFloat("PRICE");
uprs.updateFloat( "PRICE", f * percentage);
uprs.updateRow();
}
} catch (SQLException e ) {
JDBCTutorialUtilities.printSQLException(e);
} finally {
if (stmt != null) { stmt.close(); }
}
}
Basically, I have to show a list with the data from a database table [that part is working] and afterwards I have to show the highest Date [a date variable in the table]. The second part is not working no matter what I do.
Here's the code
try {
String SQL = "SELECT * FROM tb_rafael";
ResultSet rs = BD.consultar(SQL);
String tab = "";
int numReg = 0;
while (rs.next()) {
tab+="<TR>";
tab+="<TD>" + rs.getString("nme_rafael") + "</TD>";
tab+="<TD>" + rs.getString("dta_rafael") + "</TD>";
tab+="</TR>";
numReg++;
//mDat = rs2.getString("dta_rafael");
}
rs.close();
dados.put("DADOS", tab);
dados.put("NUM_REG", String.valueOf(numReg));
//Pegar Data Maior
String SQL2 = "SELECT MAX(dta_rafael) FROM tb_rafael";
ResultSet rs2 = BD.consultar(SQL2);
String mDat = "";
//while(rs2.next()){
mDat = rs2.getString("dta_rafael");
//}
rs2.close();
dados.put("MDA", mDat);
} catch (Exception ex) {
dados.put("MSG", "Erro: " + ex.getMessage());
}
What you want to look at is past the commentary line "Pegar Data Maior". That's the part that is not working. I've tried adding a while, using a different ResultSet, using the same ResultSet and none of those worked. I know it's not an issue with the SQL query since I tested it with the workbench and it returned me the data I want.
To be more specific, I don't get an error message or anything, the dados.put simply does not work and I get just this:
How the HTML code looks:
The data should show up where the {MDA} is. Anyone have any ideas?
The query SELECT MAX(dta_rafael) FROM tb_rafael may not return a column name, which you later try to retrieve, rs2.getString("dta_rafael");
I'd change the query to SELECT MAX(dta_rafael) AS Max_date..., and reference to MAX_date thereafter.
I've been testing the code over and over found that the issue is the single quote. As you can see in the query below, I used the single quote in the where clause. If I remove that I get a result but if I put it back even though the are rows that satisfies the filter it does not return anything. I also tried to use a view on this. Putting the where clause in the view and selecting the view directly and not using any filter. Still it does not return anything.
try {
Class.forName("org.postgresql.Driver").newInstance();
Connection Conn = DriverManager.getConnection("jdbc:postgresql://{ipaddress}/database?user=postgres&password=password");
Statement Stmt = Conn.createStatement();
String sqlCommand = "SELECT col1_timestamp , col2 FROM table WHERE col1_timestamp > '00:01:00' ";
ResultSet RS = Stmt.executeQuery(sqlCommand);
while (RS.next()) {
data.add(RS.getInt("col1_timestamp ")
+ "=>" + RS.getString("col2"));
}
// Clean up after ourselves
RS.close();
Stmt.close();
Conn.close();
}
catch (SQLException E) {
System.out.println("SQLException: " + E.getMessage());
System.out.println("SQLState: " + E.getSQLState());
System.out.println("VendorError: " + E.getErrorCode());
}
catch(Exception ex)
{
System.out.println(ex.getMessage());
}
I also already tried:
String sqlCommand = "SELECT col1_timestamp, col2 FROM table "
+ " WHERE col2= ? AND (now() - col1_timestamp::timestamp with time zone) < interval ? ";
PreparedStatement preparedStatement = Conn.prepareStatement(sqlCommand);
preparedStatement.setString(1, "test");
preparedStatement.setTime(2, new Time(new Long(-28680000))); //String(2, "00:02:00");
Still does not work, instead it throws an error on the second parameter.
It's pretty simple task really but it always returns a blank value.
Any idea?
The interval literals are quite limited (in SQL in general and in Postgres) and you can't use a parameter for the unit of the interval literal
If you always have the same unit (e.g. minutes) you can do something like this:
String sqlCommand =
"SELECT col1_timestamp, col2 FROM table " +
" WHERE col2= ? " +
" AND (now() - col1_timestamp::timestamp with time zone) < interval '1' minute * ?";
PreparedStatement preparedStatement = Conn.prepareStatement(sqlCommand);
preparedStatement.setString(1, "test");
preparedStatement.setInt(2, 5); // five minutes
If you need to query for different units (hours, minutes, days) then you either need to use the approriate number of minutes for each of them or change the SQL each time: interval '1' day * ? or interval '1' hour * ?
I have a mysql table user which is consisted of id, name, password and email columns.
Is there a way to create some sort of query or java code that will print in my message dialog window all of the users names.
try{
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection con = DriverManager.getConnection("jdbc:mysql://localhost/mydb","root","");
String sql = "select * from user;";
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
if (rs.next()) {
val1 = rs.getString(2);
val2 = rs.getString(3);
}
value = val1 + " " + val2;
JOptionPane.showMessageDialog(null,value);
}catch(SQLException e){
JOptionPane.showMessageDialog(null, e);
}
}
This only prints the name and the surname of the first user from the table :(
I want to print them all one below another!
If I set rs.getString(5); - it gives me an error: column index out of range.
I suggest you avoid JOptionPane for this kind of code. Better to use some Frame (Swing) and display all of the users into a separate window.
The problem with your code is that variable value is lyiong outside of the loop (which must be btw while loop, as spencer said).
try{
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection con = DriverManager.getConnection("jdbc:mysql://localhost/mydb","root","");
String sql = "select * from user;";
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
while (rs.next()) {
val = rs.getString(2) + " " + rs.getString(3);
value += val + " ";
}
JOptionPane.showMessageDialog(null,value);
}catch(SQLException e){
JOptionPane.showMessageDialog(null, e);
}
}
Try to avoid this type of code, use ArrayList and save in the array all of the users credentials. Then easily label it wherever you want.
You're only fetching the first row from the resultset. It sounds like you want a loop, and process every row from the resultset.
while (rs.next()) {
}
UPDATE
Q: It only gives me now the last user. Probably because it overwrites the val1 and val2 variable. I suppose somehow this should also goes into the loop..
A: Yes, it should go inside the loop. But I'd be populating a collection, rather than concatenating a String.
As a performance and maintenance note, you can avoid the messiness of the string concatenation in the Java by doing the concatenation in the SQL statement. I wouldn't use SELECT * and rely on the positions of two particular columns in the resultset.
I'd use a SQL statement like this:
SELECT CONCAT(u.first_name,' ',u.last_name) AS user_name FROM users
If I wasn't populating a collection, and I needed to concatenate a honkous string, I'd use a StringBuffer, e.g.
val = new StringBuffer(4096));
while (rs.next()) {
val.append(rs.getString("user_name"));
}
value = val.toString;
This question already has answers here:
ResultSet exception - before start of result set
(6 answers)
Closed 5 years ago.
I get an error stating that I got an exception before start of a result set. I'm trying to get a value (score from the MySQL database) and add one to the Java rank based on the player score. This is to create a scoreboard.
So if the player's score is lower than the current score, it gets posted with rank 1. If it's higher, the program checks the score against the next entry in the MySQL database. I haven't yet implemented a feature to change all the current entries rank's to increment by 1.
Bottom Line: I'm creating a scoreboard using MySQL and Java. The Java program creates a score entry based on input, and then sends it off to the MySQL database.
System.out.println("Your score is: "+score*2+" (A lower score is better.)");
try {
// create a java mysql database connection
String myDriver = "com.mysql.jdbc.Driver";
String myUrl = "jdbc:mysql://4.30.110.246:3306/apesbridge2013";
String dbName = "apesbridge2013";
String tbName = period + "period";
Class.forName(myDriver);
Connection conn = DriverManager.getConnection(myUrl, "user", CENSORED);
next = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
ResultSet resultSet = next.executeQuery("SELECT * FROM " + tbName);
int cscore = resultSet.getInt("score");
for(int sscore = score; sscore > cscore;){
resultSet.next();
cscore = resultSet.getInt("score");
rank++;
}
stmt = conn.createStatement();
stmt.executeUpdate("insert into " + dbName + "." + tbName + " " + "values(" + rank + ", '" + name + "', " + score + ")");
stmt.close();
conn.close();
}
catch (Exception e)
{
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
}
}
Put resultSet.next(); right below your executeQuery line.
As stated by #hd1, you need to call ResultSet.next() after the call to executeQuery:
while (resultSet.next()) {
...
Also, better to use PreparedStatement instead of java.sql.Statement and use parameter placeholders to protect against SQL Injection attacks:
There's a problem in your for loop; the exit condition should be when there are no more rows to fetch. Your query doesn't guarantee that the exit condition will ever be met, and you may attempt to fetch past the end of the resultset. (And even when your for loop does happen to be entered, and when if the for loop does happen to be exited, the rank value derived by that loop is non-deterministic, it's dependent on the order that rows are returned by the database.
I also don't see any call to resultSet.close() or next.close().
There's so many problems here, it's hard to know where to begin.
But firstly, it would be much more efficient to have the database return the rank to you, with a query:
"SELECT COUNT(1) AS rank FROM " + tbName + " WHERE score < " + score
rather than pulling back all the rows back, and comparing each score. That's just painful, and a whole lot of code that is just noise. That would allow you to focus on the code that DOES need to be there.
Once you get that working, you need to ensure that your statement is not vulnerable to SQL injection, and prepared statements with bind variables is really the way to go there.
And you really do need to ensure that calls are made to the close() methods on the resultset, prepared statements, and the connection. We typically want these in a finally block. Either use nested try/catch blocks, where the variables are immediately initialized, like this:
try {
Connection conn = DriverManager.getConnection(...
try {
stmt = conn.CreateStatement();
String query = "SELECT COUNT(1) AS `rank` FROM " + tbName + " WHERE `score` < " + score ;
try {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
rank = rs.getInt("rank");
}
} finally {
if (rs!=null) { rs.close() };
}
} finally {
if (stmt!=null) { stmt.close() };
}
} finally {
if (conn!=null) { conn.close() };
}
Or one big try/catch block can also be workable:
} finally {
if (resultSet!=null) { resultSet.close() };
if (next!=null) { next.close() };
if (conn!=null) { conn.close() };
)
The point is, the close methods really do need to be called.