The SQL code works and next() function outputs true or false but is not accepted by the if (condition).
boolean status = res.next();
if (res.next()) {
System.out.println("first");
}
if (status) {
System.out.println("second");
}
The code above has the same semantics but the one using the method next() doesn’t work.
If there is only one record in the resultset, status will be true but the next attempt of res.next() will return false. Thus, the following code will output only second.
boolean status = res.next();
if (res.next()) {
System.out.println("first");
}
if (status) {
System.out.println("second");
}
If there are two records in the resultset, you will get both, first and second as the output.
To summarize,
Output when there is only one record in the resultset
second
Output when there are two records in the resultset
first
second
What you did making the result set to move to the second row because you call next() twice
, You can check this one:
if (res.next()) {
System.out.println(“first”);
} else {
System.out.println(“second”);
}
I'm calling a Sybase stored procedure that returns multiple resultsets through JDBC.
I need to get a specific result set that has a column named "Result"
This is my code :
CallableStatement cs = conn.prepareCall(sqlCall);
cs.registerOutParameter(1, Types.VARCHAR);
cs.execute();
ResultSet rs=null;
int count = 1;
boolean flag = true;
while (count < 20000 && flag == true) {
cs.getMoreResults();
rs = cs.getResultSet();
if (rs != null) {
ResultSetMetaData resultSetMetaData = rs.getMetaData();
int columnsCount = resultSetMetaData.getColumnCount();
if (resultSetMetaData.getColumnName(1).equals("Result")) {
// action code resultset found
flag = false;
// loop on the resultset and add the elements returned to an array list
while (rs.next()) {
int x = 1;
while (x <= columnsCount) {
result.add(rs.getString(x));
x++;
}
}
result.add(0, cs.getString(1));
}
}
count++;
}
What happens here is that cs.getMoreResults returns a lot of null resultsets till it reaches the target one. I can't use cs.getMoreResults as loop condition because it returns false for null resultsets.
I put a fixed number to end the loop in condition the wanted result set wasn't returned to prevent it from going into infinite loop. It worked fine but I don't think this is right.
I think the null resultsets returned from the assignment in Sybase select #variable = value
Has anyone faced this before?
You are misinterpreting the return value of getMoreResults(). You are also ignoring the return value of execute(), this method returns a boolean indicating the type of the first result:
true: result is a ResultSet
false : result is an update count
If the result is true, then you use getResultSet() to retrieve the ResultSet, otherwise getUpdateCount() to retrieve the update count. If the update count is -1 it means there are no more results. Note that the update count will also be -1 when the current result is a ResultSet. It is also good to know that getResultSet() should return null if there are no more results or if the result is an update count (this last condition is why you get so many null values).
Now if you want to retrieve more results, you call getMoreResults() (or its brother accepting an int parameter). The return value of boolean has the same meaning as that of execute(), so false does not mean there are no more results!
There are only no more results if the getMoreResults() returns false and getUpdateCount() returns -1 (as also documented in the Javadoc)
Essentially this means that if you want to correctly process all results you need to do something like below:
boolean result = stmt.execute(...);
while(true) {
if (result) {
ResultSet rs = stmt.getResultSet();
// Do something with resultset ...
} else {
int updateCount = stmt.getUpdateCount();
if (updateCount == -1) {
// no more results
break;
}
// Do something with update count ...
}
result = stmt.getMoreResults();
}
My guess is that you are getting a lot of update counts before you get the actual ResultSet.
I am not really familiar with Sybase, but its cousin SQL Server has the 'annoying' feature to return update counts from stored procedures if you don't explicitly put SET NOCOUNT ON; at the start of the stored procedure.
NOTE: Part of this answer is based on my answer to Execute “sp_msforeachdb” in a Java application
I have the following method, but I want to use recursion; however, I get an error: "missing return statement".
static String buscar(NodoDeArbol raiz, String letra) {
if(raiz == null) {
aux="";
for (int i = 0; i < auxiliar.length()-1; i++) {
aux+=auxiliar.charAt(i);
}
return aux;
}
auxiliar = buscar(raiz.izquierdo, auxiliar+= "0");
auxiliar = buscar(raiz.derecho, auxiliar+= "1");
}
What should to do to fix this?
There are a couple of errors
First, you don't define aux (maybe is global?)
Second, you need to return a value when raiz != null
You are only returning a string when the case is null, but not returning anything when the case is not null.
You need to handle all cases. A return method (String) MUST return some sort of value.
You're if statement has the only return. You will need to add a return statement for the case that is not included in your if statement. Just judging by your current code, I'm guessing you meant to have return auxiliar; at the end of your method.
wrong is, that you return only when raiz is null, when you get parameter raiz, that is not null, method would never end - cause there is no return outside of if statement
I'm calling a Sybase stored procedure that returns multiple resultsets through JDBC.
I need to get a specific result set that has a column named "Result"
This is my code :
CallableStatement cs = conn.prepareCall(sqlCall);
cs.registerOutParameter(1, Types.VARCHAR);
cs.execute();
ResultSet rs=null;
int count = 1;
boolean flag = true;
while (count < 20000 && flag == true) {
cs.getMoreResults();
rs = cs.getResultSet();
if (rs != null) {
ResultSetMetaData resultSetMetaData = rs.getMetaData();
int columnsCount = resultSetMetaData.getColumnCount();
if (resultSetMetaData.getColumnName(1).equals("Result")) {
// action code resultset found
flag = false;
// loop on the resultset and add the elements returned to an array list
while (rs.next()) {
int x = 1;
while (x <= columnsCount) {
result.add(rs.getString(x));
x++;
}
}
result.add(0, cs.getString(1));
}
}
count++;
}
What happens here is that cs.getMoreResults returns a lot of null resultsets till it reaches the target one. I can't use cs.getMoreResults as loop condition because it returns false for null resultsets.
I put a fixed number to end the loop in condition the wanted result set wasn't returned to prevent it from going into infinite loop. It worked fine but I don't think this is right.
I think the null resultsets returned from the assignment in Sybase select #variable = value
Has anyone faced this before?
You are misinterpreting the return value of getMoreResults(). You are also ignoring the return value of execute(), this method returns a boolean indicating the type of the first result:
true: result is a ResultSet
false : result is an update count
If the result is true, then you use getResultSet() to retrieve the ResultSet, otherwise getUpdateCount() to retrieve the update count. If the update count is -1 it means there are no more results. Note that the update count will also be -1 when the current result is a ResultSet. It is also good to know that getResultSet() should return null if there are no more results or if the result is an update count (this last condition is why you get so many null values).
Now if you want to retrieve more results, you call getMoreResults() (or its brother accepting an int parameter). The return value of boolean has the same meaning as that of execute(), so false does not mean there are no more results!
There are only no more results if the getMoreResults() returns false and getUpdateCount() returns -1 (as also documented in the Javadoc)
Essentially this means that if you want to correctly process all results you need to do something like below:
boolean result = stmt.execute(...);
while(true) {
if (result) {
ResultSet rs = stmt.getResultSet();
// Do something with resultset ...
} else {
int updateCount = stmt.getUpdateCount();
if (updateCount == -1) {
// no more results
break;
}
// Do something with update count ...
}
result = stmt.getMoreResults();
}
My guess is that you are getting a lot of update counts before you get the actual ResultSet.
I am not really familiar with Sybase, but its cousin SQL Server has the 'annoying' feature to return update counts from stored procedures if you don't explicitly put SET NOCOUNT ON; at the start of the stored procedure.
NOTE: Part of this answer is based on my answer to Execute “sp_msforeachdb” in a Java application
I have an insertOrUpdate method which inserts an Entity when it doesn't exist or update it if it does. To enable this, I have to findByIdAndForeignKey, if it returned null insert if not then update. The problem is how do I check if it exists? So I tried getSingleResult. But it throws an exception if the
public Profile findByUserNameAndPropertyName(String userName, String propertyName) {
String namedQuery = Profile.class.getSimpleName() + ".findByUserNameAndPropertyName";
Query query = entityManager.createNamedQuery(namedQuery);
query.setParameter("name", userName);
query.setParameter("propName", propertyName);
Object result = query.getSingleResult();
if (result == null) return null;
return (Profile) result;
}
but getSingleResult throws an Exception.
Thanks
Throwing an exception is how getSingleResult() indicates it can't be found. Personally I can't stand this kind of API. It forces spurious exception handling for no real benefit. You just have to wrap the code in a try-catch block.
Alternatively you can query for a list and see if its empty. That doesn't throw an exception. Actually since you're not doing a primary key lookup technically there could be multiple results (even if one, both or the combination of your foreign keys or constraints makes this impossible in practice) so this is probably the more appropriate solution.
Try this in Java 8:
Optional first = query.getResultList().stream().findFirst();
I encapsulated the logic in the following helper method.
public class JpaResultHelper {
public static Object getSingleResultOrNull(Query query){
List results = query.getResultList();
if (results.isEmpty()) return null;
else if (results.size() == 1) return results.get(0);
throw new NonUniqueResultException();
}
}
Here's a good option for doing this:
public static <T> T getSingleResult(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
I've done (in Java 8):
query.getResultList().stream().findFirst().orElse(null);
From JPA 2.2, instead of .getResultList() and checking if list is empty or creating a stream you can return stream and take first element.
.getResultStream()
.findFirst()
.orElse(null);
Spring has a utility method for this:
TypedQuery<Profile> query = em.createNamedQuery(namedQuery, Profile.class);
...
return org.springframework.dao.support.DataAccessUtils.singleResult(query.getResultList());
If you wish to use the try/catch mechanism to handle this problem.. then it can be used to act like if/else. I used the try/catch to add a new record when I didn't find an existing one.
try { //if part
record = query.getSingleResult();
//use the record from the fetched result.
}
catch(NoResultException e){ //else part
//create a new record.
record = new Record();
//.........
entityManager.persist(record);
}
Here's a typed/generics version, based on Rodrigo IronMan's implementation:
public static <T> T getSingleResultOrNull(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
There is an alternative which I would recommend:
Query query = em.createQuery("your query");
List<Element> elementList = query.getResultList();
return CollectionUtils.isEmpty(elementList ) ? null : elementList.get(0);
This safeguards against Null Pointer Exception, guarantees only 1 result is returned.
So don't do that!
You have two options:
Run a selection to obtain the COUNT of your result set, and only pull in the data if this count is non-zero; or
Use the other kind of query (that gets a result set) and check if it has 0 or more results. It should have 1, so pull that out of your result collection and you're done.
I'd go with the second suggestion, in agreement with Cletus. It gives better performance than (potentially) 2 queries. Also less work.
Combining the useful bits of the existing answers (limiting the number of results, checking that the result is unique) and using the estabilshed method name (Hibernate), we get:
/**
* Return a single instance that matches the query, or null if the query returns no results.
*
* #param query query (required)
* #param <T> result record type
* #return record or null
*/
public static <T> T uniqueResult(#NotNull TypedQuery<T> query) {
List<T> results = query.setMaxResults(2).getResultList();
if (results.size() > 1) throw new NonUniqueResultException();
return results.isEmpty() ? null : results.get(0);
}
The undocumented method uniqueResultOptional in org.hibernate.query.Query should do the trick. Instead of having to catch a NoResultException you can just call query.uniqueResultOptional().orElse(null).
I solved this by using List<?> myList = query.getResultList(); and checking if myList.size() equals to zero.
Look this code :
return query.getResultList().stream().findFirst().orElse(null);
When findFirst() is called maybe can be throwed a NullPointerException.
the best aproach is:
return query.getResultList().stream().filter(Objects::nonNull).findFirst().orElse(null);
Here's the same logic as others suggested (get the resultList, return its only element or null), using Google Guava and a TypedQuery.
public static <T> getSingleResultOrNull(final TypedQuery<T> query) {
return Iterables.getOnlyElement(query.getResultList(), null);
}
Note that Guava will return the unintuitive IllegalArgumentException if the result set has more than one result. (The exception makes sense to clients of getOnlyElement(), as it takes the result list as its argument, but is less understandable to clients of getSingleResultOrNull().)
Here's another extension, this time in Scala.
customerQuery.getSingleOrNone match {
case Some(c) => // ...
case None => // ...
}
With this pimp:
import javax.persistence.{NonUniqueResultException, TypedQuery}
import scala.collection.JavaConversions._
object Implicits {
class RichTypedQuery[T](q: TypedQuery[T]) {
def getSingleOrNone : Option[T] = {
val results = q.setMaxResults(2).getResultList
if (results.isEmpty)
None
else if (results.size == 1)
Some(results.head)
else
throw new NonUniqueResultException()
}
}
implicit def query2RichQuery[T](q: TypedQuery[T]) = new RichTypedQuery[T](q)
}
So all of the "try to rewrite without an exception" solution in this page has a minor problem. Either its not throwing NonUnique exception, nor throw it in some wrong cases too (see below).
I think the proper solution is (maybe) this:
public static <L> L getSingleResultOrNull(TypedQuery<L> query) {
List<L> results = query.getResultList();
L foundEntity = null;
if(!results.isEmpty()) {
foundEntity = results.get(0);
}
if(results.size() > 1) {
for(L result : results) {
if(result != foundEntity) {
throw new NonUniqueResultException();
}
}
}
return foundEntity;
}
Its returning with null if there is 0 element in the list, returning nonunique if there are different elements in the list, but not returning nonunique when one of your select is not properly designed and returns the same object more then one times.
Feel free to comment.
I achieved this by getting a result list then checking if it is empty
public boolean exist(String value) {
List<Object> options = getEntityManager().createNamedQuery("AppUsers.findByEmail").setParameter('email', value).getResultList();
return !options.isEmpty();
}
It is so annoying that getSingleResult() throws exceptions
Throws:
NoResultException - if there is no result
NonUniqueResultException - if more than one result
and some other exception that you can get more info on from their documentation
I prefer #Serafins answer if you can use the new JPA features, but this is one fairly straight forward way to do it which I'm surprised hasn't been mentioned here before:
try {
return (Profile) query.getSingleResult();
} catch (NoResultException ignore) {
return null;
}
`public Example validate(String param1) {
// TODO Auto-generated method stub
Example example = new Example();
Query query =null;
Object[] myResult =null;
try {
query = sessionFactory.getCurrentSession()
.createQuery("select column from table where
column=:p_param1");
query.setParameter("p_param1",param1);
}
myResult = (Object[])query.getSingleResult();//As your problem occurs here where the query has no records it is throwing an exception
String obj1 = (String) myResult[0];
String obj2 = (String) myResult[1];
example.setobj1(ISSUtil.convertNullToSpace(obj1))
example.setobj2(ISSUtil.convertNullToSpace(obj2));
return example;
}catch(Exception e) {
e.printStackTrace();
example.setobj1(ISSUtil.convertNullToSpace(""));//setting
objects to "" in exception block
example.setobj1(ISSUtil.convertNullToSpace(""));
}
return example;
}`
Answer : Obviously when there is no records getsingleresult will throw an exception i have handled it by setting the objects to "" in the exception block even though it enter the exception you JSON object will set to ""/empty
Hope this is not a perfect answer but it might help
If some needs to modify my code more precisely and correct me always welcome.
Thats works to me:
Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : null;