Incomplete ResultSet data - java

Comment comment;
ArrayList<Comment> commentList = null;
try{
ConnectionFactory myFactory = ConnectionFactory.getFactory();
Connection conn = myFactory.getConnection();
int i = 1; int j = 1; int k = 1;
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM COMMENT WHERE deletestatus = 0 and workid = ?");
PreparedStatement pstmtLName = conn.prepareStatement("SELECT * FROM LEADER WHERE leaderid = ?");
PreparedStatement pstmtMName = conn.prepareStatement("SELECT * FROM MEMBER WHERE memberid = ?");
pstmt.setInt(i++, Integer.parseInt(projid));
ResultSet rs = pstmt.executeQuery();
System.out.print(rs);
commentList = new ArrayList<Comment>();
while(rs.next())
{
comment = new Comment();
comment.setDetails(rs.getString("details"));
comment.setDateadded(rs.getTimestamp("dateadded"));
comment.setUrgency(rs.getInt("urgency"));
if(rs.getInt("leaderid") != 0){
comment.setLeaderid(rs.getInt("leaderid"));
pstmtLName.setInt(j++, rs.getInt("leaderid"));
ResultSet rs2 = pstmtLName.executeQuery();
if(rs2.next()){
comment.setFullname(rs2.getString("firstname") +" " + rs2.getString("lastname"));
}
}
if(rs.getInt("memberid") != 0) {
comment.setMemberid(rs.getInt("memberid"));
System.out.print("in the loop");
pstmtMName.setInt(j++, rs.getInt("memberid"));
ResultSet rs3 = pstmtMName.executeQuery();
if(rs2.next()){
comment.setFullname(rs3.getString("firstname") +" " + rs3.getString("lastname"));
}
}
comment.setProjid(Integer.parseInt(projid));
commentList.add(comment);
}
return commentList;
}
The problem with the code above is that it only gives back the first result of the result set.
When i removed both of the IF clauses in the WHILE(RS.NEXT) clause, it returned all the needed results but incomplete information because what i also need the query inside the if statement.
Please do help if you guys know the exact problem and tell me if you guys need more info. Thank you!

Here, The problem seems at
pstmtLName.setInt(j++, rs.getInt("leaderid"));
pstmtMName.setInt(j++, rs.getInt("memberid"));
The value of j would be increased for each true condition till loop iteration.
Thus,it increases your parameterIndex of prepapred statement.
It should be
pstmtLName.setInt(1, rs.getInt("leaderid"));
pstmtMName.setInt(1, rs.getInt("memberid"));

You have defined int k but did not use it. I assume you wanted to use it to set memberid parameter.
Change
pstmtMName.setInt( j++, rs.getInt( "memberid" ) );
to
pstmtMName.setInt( k++, rs.getInt( "memberid" ) );
and it should be working.
And I wonder why you use i++, j++ and k++ to set the param values of the statement when there is only one parameter marker ? seen in the query. You should directly be using pstObject.setInt( 1, .... Otherwise, if rs fetches more than a record where leaderid != 0 and memberid != 0, they would cause an increment for the marker index, say pstObject.setInt( 2, ..., which is an invalid parameter in your query case and throws and SQLException.
As you are repeatedly using the same pstObject in a while loop, I would like to suggest using pstObject.clearParameters() to clear current parameter values. Though this is optional, in some cases it is useful to immediately release the resources used by the current parameter values.

Related

how to execute prepared statement in a for loop to fetch data from tables in jsp?

what is wrong in this code? I am getting this error.
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'attendance where sub_id='3' and reg_no='1111'' at line 1
Code
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/sms", "root", "*****");
int k;
String sub = "";
int t_class[] = new int[counter];
int att_class[] = new int[counter];
int tallo_class[] = new int[counter];
PreparedStatement ps3;
PreparedStatement ps4;
PreparedStatement ps5;
for (k = 0; k < (counter - 1); k++) {
sub = subjects_id[k];
//START : getting total no of classes held
ps3 = con.prepareStatement("SELECT COUNT(*) FORM attendance where sub_id=? and reg_no=?");
ps3.setString(1, sub);
ps3.setString(2, reg_no);
ResultSet rs3 = ps3.executeQuery();
rs3.next();
t_class[k] = rs3.getInt(1);
}
}
So one big tip is you want to prepare your statement outside of the loop. That is kind of the point of preparing it(Also, parameterizing the inputs). You can re-use the statement, then as stated above you misspelled the word FROM.
PreparedStatement statement = con.prepareStatement("SELECT COUNT(*) FROM attendance where sub_id=? and reg_no=?");
for (int i = 0; i < (k - 1); i++) {
statement.setString(1, sub);
statement.setString(2, reg_no);
ResultSet rs3 = ps3.executeQuery();
rs3.next();
t_class[k] = rs3.getInt(1);
}
There is a typo in your SQL query. You have given FROM as FORM. It should be
ps3 = con.prepareStatement("SELECT COUNT(*) FROM attendance where sub_id=? and reg_no=?");
Also since you are using the same PreparedStatement throughout the loop, then its better you keep the PreparedStatement outside the loop. If you have sql statment which keeps changing inside the loop, then only its worth using it in the loop. If its keep changing, then just use Statement instead of PreparedStatement, else the very purpose of PreparedStatement is lost as you keep changing it.
It should be FROM instead of FORM. The error message clearly indicates that the issue is after the required FROM keyword.
ps3 = con.prepareStatement("SELECT COUNT(*) FROM attendance where sub_id=? and reg_no=?");

Can you stop checking a if once it has passed once, in a while loop?

I don't need the if after its condition has been met. Is there any way I can modify my code so that it doesn't have to check for it after it passed?
I have a lot of tables in my database and I'm wondering if the code is optimal.
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM STACKOVERFLOW.information_schema.tables ORDER BY TABLE_NAME");
while (rs.next()) {
String name = rs.getString("TABLE_NAME");
ExtractFrom.addItem(name);
if (name.toLowerCase().equals("stack")) pvIsPresent=true;
}
if (pvIsPresent)
ExtractFrom.setSelectedItem("stack");
You could just do if (!pvIsPresent && name.toLowerCase().equals("stack")).
Although you might also want to use the slightly more efficient name.equalsIgnoreCase("stack").
This is somehow ugly but...
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM STACKOVERFLOW.information_schema.tables ORDER BY TABLE_NAME");
while (rs.next()) {
String name = rs.getString("TABLE_NAME");
ExtractFrom.addItem(name);
if (name.toLowerCase().equals("stack")) {
pvIsPresent = true;
break;
}
}
while (rs.next()) {
String name = rs.getString("TABLE_NAME");
ExtractFrom.addItem(name);
}
if (pvIsPresent)
ExtractFrom.setSelectedItem("stack");
You could change the while statement to this:
while(rs.next && !pvIsPresent)...
More ugly and more simply maybe but you can put a counter before while as
"int counter = 0"
and in the if statement you can ask as
"if(..... && counter == 0)"
than after if statement you can increment the counter as
"counter++"
than since the counter never become 0 again the if statement never be checked again.
I hope it helps too.

Building a String parameter (with SQL content) from resource file for SQL PreparedStatement

I need to execute a SQL PreparedStatement in Java using jdbc.
I'm facing problems with one of the parameters because it has SQL content and also Strings from a resource file.
It looks something like this:
Required SQL:
SELECT * FROM Table T WHERE T.value = 10 AND T.display IN ('Sample1', 'Sample2')
In the above query, the Sample1 and Sample2 values must be passed through a parameter to a PreparedStatement.
PreparedStatement:
SELECT * FROM Table T WHERE T.value = 10 ?
In my application code I'm setting the parameters like:
statement.setString(1, "AND T.display IN ('Sample1', 'Sample2')");
However this is not returning the appropriate results.
Is there a better way to build this particular parameter considering it has SQL content and Strings too?
EDIT:
Sample1, Sample2 etc. are strings that are retrieved from an external file at run-time and there can be different number of these strings each time. I.e. there can be only one string Sample1 or multiple strings Sample1, Sample2, Sample3, etc..
EDIT2:
Database being used is Oracle.
The ? placeholder can only be used in a position where a value is expected in the query. Having a ? in any other position (as in your question: WHERE T.value = 10 ?) is simply a syntax error.
In other words: it is not possible to parametrize part of the query itself as you are trying to do; you can only parametrize values. If you need to add a dynamic number of parameters, you will need to construct the query dynamically by adding the required number of parameters and using setString(). For example:
StringBuilder sb = new StringBuilder(
"SELECT * FROM Table T WHERE T.value = 10 AND T.display IN (?");
// Note: intentionally starting at 1, first parameter already above
// Assuming always at least 1 parameter
while (int i = 1; i < params.length; i++) {
sb.append(", ?");
}
sb.append(')');
try (
PreparedStatement pstmt = con.prepareStatement(sb.toString())
) {
for (int i = 0; i < params.length; i++) {
pstmt.setString(i + 1, params[i]);
}
try (
ResultSet rs = pstmt.executeQuery();
) {
// Use resultset
}
}
Use this as PreparedStatement
"SELECT * FROM Table T WHERE T.value = 10 AND T.display IN (?, ?);"
and then call
statement.setString(1, "Sample1");
statement.setString(2, "Sample2");
before executing the statement.
Update:
String generateParamString(int params) {
StringBuilder sb = new StringBuilder("(");
for (int i = 1; i < params; i++) {
sb.append("?, ");
}
sb.append("?)");
return sb.toString();
}
List<String> samples = ... // your list with samples.
String stmtString = "SELECT * FROM Table T WHERE T.value = 10 AND T.display IN "
+ generateParamString(samples.size());
// generate statement with stmtString
for (int i = 0; i < samples.size(); i++) {
statement.setString(i + 1, samples.get(i));
}
// execute statement...

getColumnCount does not count the column when its value is null?

I have this code:
// Get the results
while(rs.next())
{
resultList = new JSONObject();
for(int i = 1; i <= rsmd.getColumnCount(); i++)
{
resultList.put(rsmd.getColumnName(i) , rs.getString(i));
}
}
It appears that rsmd.getColumnCount() does not count the columns for which the corresponding value is null. Is there any workaround for this ?
Depending on the time of the day, the same SQL returns values and/or nulls and I would like to get the same number of columns each time.
Cheers,
Tim
This is JAVA of course - and I used the "Null" tag because the getColumnCount tag was refused because I am lacking "reputation points" on this site.
I think getColumnCount is not counting the null entries because I have 2 entries in my DB, one with a few null entries and the other one with no null entries.
getColumnCount only returns the count for entries with actual values.
Problem solved: The problem was not getColumnCount(), but the
resultList.put(rsmd.getColumnName(i) , rs.getString(i));
The Put method did not add anything when rs.getString(i) returned null.
What induced me into error was that a print of these values did show the null.
Did you try to put some flag on your query? If it's null then put something and you can catch these on your code.
I have a similar problem, but it is not related to nulls, I just get a totally wrong answer back from getColumnCount(). My workaround uses a separate ResultSet, thusly:
// Get the results
DatabaseMetaData metadata = null;
ResultSet rs = null;
int columnCount = 0;
try {
metadata = connection.getMetaData();
rs = metadata.getColumns(null, "YOURSCHEMA", "YOURTABLE", null);
while (column.next()) {
columnCount++;
}
} catch (Exception e) {
e.printStackTrace();
}
/* note here you must re-fill your rs or create a new one since it cannot be reset
with a call to rs.first() as it is a forward-only collection, with something like */
// rs = statement.executeQuery("SELECT * FROM yourschema.yourtable");
while(rs.next())
{
resultList = new JSONObject();
for(int i = 1; i <= rsmd.getColumnCount(); i++)
{
resultList.put(rsmd.getColumnName(i) , rs.getString(i));
}
}

MySQL + JAVA Exception: Before start of result set [duplicate]

This question already has answers here:
ResultSet exception - before start of result set
(6 answers)
Closed 5 years ago.
try
{
PreparedStatement s = (PreparedStatement) conn.prepareStatement("SELECT voters.Check,count(*) FROM voting.voters where FirstName="+first+"and LastName="+last+" and SSN="+voter_ID);
//java.sql.Statement k = conn.createStatement();
rs=s.executeQuery();
//s.executeQuery("SELECT voters.Check,count(*) FROM voting.voters where FirstName="+first+"and LastName="+last+" and SSN="+voter_ID);
System.out.println(rs.first());
c=rs.getInt(1);
d=rs.getInt(2);
System.out.println(c);
System.out.println(d);
if(c==1 && d==1)
{
s.executeUpdate("update cand set total=total+1 where ssn="+can_ID);
System.out.println("Succeful vote");
System.out.println("after vote");
s.executeUpdate("update voters set voters.Check=1 where ssn="+voter_ID);
toclient=1;
PreparedStatement qw = (PreparedStatement) conn.prepareStatement("select FirstName from cand where ssn="+can_ID);
// rs=k.executeQuery("select FirstName from cand where ssn="+can_ID);
rs1 = qw.executeQuery();//Error Here Plz help me
String name1= (String) rs1.getString(1);
System.out.println(name1);
s.executeUpdate("update voters set VTO="+name1+"where ssn="+voter_ID);
System.out.println(rs.getString(1));
}
else
{
if(c != -1)
toclient =2;
if( d ==0)
toclient =3;
if( d>1)
toclient =4;
}
System.out.println("out-----------");
rs.close();
s.close();
}
catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Error IS :
java.sql.SQLException: Before start of result set
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1072)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:986)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:981)
The common practice is to use rs.next() method with while cycle:
PreparedStatement st = conn.prepareStatement("select 1 from mytable");
ResultSet rs = st.executeQuery();
while (rs.next()) {
// do something with result set
}
rs.close();
st.close();
I've omitted try/catch/finally clauses for clarity. Note that you should invoke each close() method in separate finally block.
While rs1.first() may work, to avoid exception I would like to avoid it and use rs1.next() instead.
See javadoc of ResultSet.first():
SQLException - if a database access error occurs; this method is called on a closed result set or the result set type is TYPE_FORWARD_ONLY
SQLFeatureNotSupportedException - if the JDBC driver does not support this method
while next doesn't have this limitation
Code:
if (rs1.next()) {
String name1 = rs1.getString(1);
}
Tips: avoid useless type casting (your code is full of them)
In your code snippet you create PreparedStatements but you do not use them correctly. Prepared statements are meant to be used as a kind of 'statement template' which is bound to values before it executes. To quote the javadoc:
PreparedStatement pstmt = con.prepareStatement(
"UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?");
pstmt.setBigDecimal(1, 153833.00)
pstmt.setInt(2, 110592)
This has two big advantages over your current usage of PreparedStatement:
one PreparedStatement can be used for multiple executes
it prevents a possible SQL injection attack
The second one here is the biggie, if for instance your variables first and last are collected in a user interface and not reformatted, you run the risk of parts of SQL being input for those values, which then end up in your statements! Using bound parameters they will just be used as values, not part of the SQL statement.
When you get a resultset, the cursor is placed before the first row. Trying to get anything before moving your cursor to the first row will cause the error you received. You need to move the cursor to the first row using this line:
rs1.first();
before calling
String name1 = (String) rs1.getString(1);
Of course, make sure the resultset contains entries before calling rs1.getString(1).
Call rs1.first() before using the ResultSet.
Moves the cursor to the first row in this ResultSet object.
Initially the cursor position of the ResultSet is before the start of the set. The first() method returns true if there is data in the set. So preferably:
if (rs1.first()) {
String name1 = (String) rs1.getString(1);
}
So, to be sure the proper use of PreparedStatment, here is your original example adjusted for best practices (note the cast is redundant):
PreparedStatement s = conn.prepareStatement(
"SELECT voters.Check,count(*) " +
"FROM voting.voters " +
"where FirstName=? and LastName=? and SSN=?");
s.setString(1,first);
s.setString(2,last);
s.setString(3,voter_ID);
ResultSet rs = s.executeQuery();
while( rs.next() ) {
c = rs.getInt(1);
d = rs.getInt(2);
}
Hope this helps... :)

Categories