ResultSet not populating with results - java

I am attempting to pull results from an Oracle database. I have written a query that is correct, and produces accurate results when issued manually in sqlplus. Furthermore, the code works as expected when when the query matches only one row (In other words, when the ResultSet has only one row, everything works). However, when more than one row match the query, the ResultSet returned by the Oracle JDBC is empty.
public Component[] getAllComponents(int typeId, int osId) throws SQLException
{
String query= "SELECT c.component_id, c.component_name, c.component_version, c.type_id, c.post_download_instructions, "
+ "o.os_id, o.os_name, o.description AS os_description, "
+ "i.file_location, i.release_date, i.patch_number, i.file_id, "
+ "i.description AS i_description "
+ "FROM components c, installation_files i, operating_systems o "
+ "WHERE c.type_id = ? "
+ "AND i.os_id = ? "
+ "AND c.component_id = i.component_id "
+ "AND i.os_id = o.os_id";
ResultSet results = null;
PreparedStatement stmt = null;
ArrayList<Component> found = new ArrayList<Component>();
try {
stmt = dbConn.prepareStatement(query); //dbConn is member variable
stmt.setInt(1, typeId);
stmt.setInt(2, osId);
results = stmt.executeQuery();
while(results.next()){
//Some logic
}
} finally {
if(results != null) results.close();
if(stmt != null) stmt.close();
dbConn.close();
}
//More Code
//etc. etc.
Inspecting the ResultSet shows that calling ResultSet.next() never produces true when the fetched results should contain more than one row. However, issuing the query manually does produce results, and when only one row is returned, everything works fine. Does anyone know what's going on? I'm using Oracle's ojdbc6.jar.
Thanks!

Before that query you can check if there really are some components with COUNT(*) instead of all fields. Then run your query only if COUNT(*) is one or more.

Related

Java JDBC SQL Query Result Inconsistency

Submitting a query from SQLiteStudio returns the expected result from a View.
However, when the same query is sent from my program in java, the result is different for some queries.
ie: SELECT Rev FROM PartRevs WHERE PartNumber = '800111'
This returns the expected result of "B" when executed within SQLiteStudio. However, then the same query is executed from JAVA, it returns "A". Only one result is returned with both queries.
This does not happen consistently. Most queries work, but it occasionally does not work.
The 'Rev' or Revision of a given part is pulled from another table called 'ECO_TDA_Linewise'. Each time a new revision is released for a given part, a new line is added with increasing index numbers.
I believe the problem comes from the way the 'PartRevs' view works. Of the many other tables and queries, this is the only one that has an issue.
Here are the code blocks that interact with the database:
public String GetRevision(String PartNumber) {
String sqlStatement = "SELECT Rev FROM PartRevs WHERE PartNumber = '" + PartNumber + "'";
return getDatabaseResult(sqlStatement, "Rev");
}
public String getDatabaseResult(String sqlStatement, String Column) {
String result = "";
try (Connection conn = FulfillmentWorkorders.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sqlStatement)) {
result = rs.getString(Column);
conn.close();
} catch (SQLException e) {
System.out.println("\"" + sqlStatement + "\" throws exception: " + e.getMessage());
}
return result;
}

HOW to write select query in java using jdbc where to need to check if COLUMN IS NULL?

Trying to write condition where ind is null in the select query in java using jdbc oracle driver.
code :
Done all the DB connectivity
info.add("CN");
info.add("NULL");
Tried:
ResultSet rs1 = st.executeQuery("select COUNT(*) from TABLENAME where A='" + info.get(i) + " and ind is'" +info.get(i+1) + " '");
Note: using oracle driver JDBC API.
Taking the null value from array list.but it does not fetch proper values from DB.
code:
Done all the DB connectivity
info.add("CN");
info.add("NULL");
ResultSet rs1 = st.executeQuery("select COUNT(*) from TABLENAME where A='" + info.get(i) + " and ind IS '" +info.get(i+1) + " '");
I expect the output like count(no of rows):
BAsic sql query if used in DB:
select COUNT(*)
from TABLENAME
where A= 'a'
and ind IS null;
First handling NULL is different than handling a value:
ind IS NULL
ind = '...'
This makes it difficult to use a prepared statement. But a PreparedStatement should be used, not only for securite (against SQL injection) but also to escape single quotes and such. And is type-safe in that it uses types & conversions.
Oracle SQL has a defect in that it does not distinghuish between NULL and '', so you could go for '' instead. Oracle independent would be:
// Typed fields:
String a = ...;
int n = ...;
String ind = null;
String sql = ind == null
? "select COUNT(*) from TABLENAME where A=? and n=? and ind is null"
: "select COUNT(*) from TABLENAME where A=? and n=? ind = ?";
try (PreparedStatement stmt = new PreparedStatement(sql)) {
stmt.setString(1, a);
stmt.setInt(2, n);
if (ind != null) {
stmt.setString(3, ind);
}
try (ResultSet rs = stmt.executeQuery()) {
long count = rs.next() ? rs.getLong(1) : 0L;
return count;
}
}
Try-with-resources closes statement and result set, also with thrown exception or return in the middle.
For a general Object list, one could use one for loop constructing the SQL template, and a second for setting the PreparedStatement's fields.
This part:
" and ind is'" +info.get(i+1) + " '");
generates the following SQL:
and ind is 'NULL ';
which is wrong because it will throw an error:
ORA-00908: missing NULL keyword
You need to change that to:
" and ind is " +info.get(i+1));
but then it won't work any more for not null values.

Prepared Statement setString adding unnecessary single quotes to String

Background
I am trying to set the contents of an ArrayList into an IN clause in a Db2 SQL statement. I am using the PreparedStatement to build my query. This is our coding standard.
What I tried #1
I researched a couple ways to achieve this. I first tried using the setArray() as show in this question: How to use an arraylist as a prepared statement parameter The result was I was getting a error of Err com.ibm.db2.jcc.am.SqlFeatureNotSupportedException: [jcc][t4][10344][11773][3.65.110] Data type ARRAY is not supported on the target server. ERRORCODE=-4450, SQLSTATE=0A502 After this roadblock, I moved on to #2
What I tried #2
I then tried using the Apache Commons StringUtils to convert the ArrayList into a comma separated String like I needed for my IN clause. The result is that this did exactly what I needed, I have a single String with all my results separated by a comma.
The problem:
The setString() method is adding single quotes to the beginning and end of my String. I have used this many times, and it has never done this. Does anyone know if there is a way around this, or an alternative using the PreparedStatement?? If I use String concatenation my query works.
Code (explained above):
List<String> selectedStatuses = new ArrayList<String>(); //Used to store contents of scoped var
//Get Contents of Checkbox which are in the form of a List
selectedStatuses = (List) viewScope.get("selectedStatuses");
String selectedStatusesString = StringUtils.join(selectedStatuses, ",");
.... WHERE ATM_DET_ATM_STAT IN (?)";
ps.setString(1, selectedStatusesString);
Log Value showing correct value of String
DEBUG: selectedStatusesString: 'OPEN','CLOSED','WOUNDED','IN PROGRESS'
Visual of incorrect result
The quotes at the beginning and end are the problem.
For an IN clause to work, you need as many markers as you have values:
String sql = "SELECT * FROM MyTable WHERE Stat IN (?,?,?,?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, "OPEN");
stmt.setString(2, "CLOSED");
stmt.setString(3, "WOUNDED");
stmt.setString(4, "IN PROGRESS");
try (ResultSet rs = stmt.executeQuery()) {
// use rs here
}
}
Since you have a dynamic list of values, you need to do this:
List<String> stats = Arrays.asList("OPEN", "CLOSED", "WOUNDED", "IN PROGRESS");
String markers = StringUtils.repeat(",?", stats.size()).substring(1);
String sql = "SELECT * FROM MyTable WHERE Stat IN (" + markers + ")";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int i = 0; i < stats.size(); i++)
stmt.setString(i + 1, stats.get(i));
try (ResultSet rs = stmt.executeQuery()) {
// use rs here
}
}
Starting with Java 11, StringUtils is no longer needed:
String markers = ",?".repeat(stats.size()).substring(1);
Use two apostrophes '' to get a single apostrophe on DB2, according to the DB2 Survival Guide. Then call .setString().
To anyone else experiencing the issue with single quotes, I had to modify my function so that it doesn't use ? to set the value; instead, I just treat the entire query as a string:
public static void runQuery(String tableName, String columnName, int value, String whereName, String whereValue) {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("UPDATE " + tableName + " SET " + columnName + " = " + value + " WHERE " + whereName + " = " + "'" + whereValue + "'")) {
ps.executeUpdate();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
Hope this helps

JDBC MySQL DML Statement Insert with Nested Select Performance

FYI - I'm not a developer, but write code when I have to :) Trying to write some java code to update a database in a batched fashion for multiple records. As I'm inserting new rows, I'm querying another table to find relevant data to add relevant date.
The code seems to work, but my problem is performance. I'm seeing that the full batch of dml statements take about 1 second per statement to execute. I'm updating several thousand records, so this job will take quite awhile to execute. So, what I'm looking for is any other ideas on how I can do this while maximizing performance.
Here's what I'm doing right now.
for(Referrer_UpdateSet i : referrerUpdateSet)
{
String dmlStatement = "INSERT INTO TempRefURL (firstTouchDate) " +
"(SELECT activityDateTime as firstTouch "+
"FROM referrer_URL_backup_10292014 "+
"WHERE mktPersonId = ? "+
"ORDER BY activityDateTime ASC LIMIT 1)";
stmt = mktoUTMConn.prepareStatement(dmlStatement);
stmt.setInt(1, i.id);
//System.out.println(stmt+" \n");
stmt.executeUpdate();
}
mktoUTMConn.commit();
I'm also trying preparedStatements.addBatch, but it doesn't seem to be working (only 1 row inserted..)
System.out.println("updating temp table with referrer URL data");
//iterate through array of parsed referrer URLs
String dmlStatement = "UPDATE dml_sandbox.TempRefURL SET Referrer_URL = ? " + "WHERE id = ?";
for(Referrer_UpdateSet i : referrerUpdateSet){
stmt = mktoUTMConn.prepareStatement(dmlStatement);
stmt.setInt(2, i.id);
stmt.setString(1, i.cleanURL);
//System.out.println(stmt+" \n");
stmt.addBatch();
//stmt.executeUpdate();
//System.out.println(stmt+" \n");
}
stmt.executeBatch();
System.out.println("Done updating temp table with referrer URL data");
mktoUTMConn.commit();
Any suggestions would be greatly appreciated. Thanks!
Simple fix. See my comment above. Here's the new code:
String dmlStatement = "UPDATE dml_sandbox.TempRefURL SET Referrer_URL = ? " + "WHERE id = ?";
stmt = mktoUTMConn.prepareStatement(dmlStatement);
//iterate through array of parsed referrer URLs
for(Referrer_UpdateSet i : referrerUpdateSet){
stmt.setInt(2, i.id);
stmt.setString(1, i.cleanURL);
stmt.addBatch();
stmt.executeUpdate();
}
System.out.println(stmt+" \n");
int[] recordsAffected = stmt.executeBatch();
System.out.println("Done updating temp table with referrer URL data");
System.out.println(recordsAffected.length + " records affected");
mktoUTMConn.commit();

Java JDBC Retrieve ID After Insert

I use triggers to set PK column values of all tables so i do not do any operation about IDs in java but i need the ID after insert.
How can i get the ID?
stat.execute("INSERT INTO TPROJECT_PROCESS_GROUP(NPROJECT_ID,VDESCRIPTION) " +
"VALUES(" +
"'" + projectID + "'," +
"'" + description + "'" +
"");
Edit: Hi again I read the question, now I get an exception like 'unsupported operation'(i translated from my native language the exact english form might be different). i guess this is about oracle's support for GetGeneratedKeys? Do you know anything about this?
Solution: As mentioned in a book about callablestatements This statement can be used to execute stored procedures and functions. Unlike the PreparedStatement, most databases do not perform any preparation for the call,because it is such a simple command. The CallableStatement instances can be used toreturn the object that the stored procedure—or function, to be more exact—returned.
OracleConnection conn = null;
//OraclePreparedStatement pstat = null;
OracleCallableStatement cstat = null;
String sql = "BEGIN INSERT INTO TPROJECT P (VPROJECT_TITLE,VPROJECT_DESC) VALUES(?,?) RETURNING P.NPROJECT_ID INTO ?; END;";
try {
conn = ConnectionUtility.GetConnection();
cstat = (OracleCallableStatement)conn.prepareCall(sql);
cstat.setString(1, title);
cstat.setString(2, description);
cstat.registerOutParameter(3, OracleTypes.NUMBER);
cstat.execute();
int returnedID = cstat.getInt(3);
// System.out.println(returnedID);
conn.close();
return returnedID;
This example is how you would do it in PostgreSQL. Hopefully you can do something similar in Oracle.
This is how you get the id after INSERT INTO for auto-generated keys like serial . Important here is to provide RETURN_GENERATED_KEYS in the prepareStatement() call.
Resultset result;
PreparedStatement prep;
String query = "INSERT INTO myRel (data) VALUES (?)";
prep = db.prepareStatement(query ,Statement.RETURN_GENERATED_KEYS);
result = prep.getGeneratedKeys();
if(result.next() && result != null){
System.out.println("Key: " + result.getInt(1));
} else {
System.out.println("No, Nop nada");
}
Hope that helps someone :)

Categories