Java.sql - Error while nesting CAST into MAX - java

I am trying to execute the following query:
select MAX(CAST(T.progress AS DECIMAL)) as maxProgress from default_APN_TRACKING T where T.smartlet = 'Life-Pension Selector' GROUP BY T.trackingId
Which throws me the following Exception:
java.lang.Exception: Exception on sql query:select MAX(CAST(T.progress AS DECIMAL)) as maxProgress from default_APN_TRACKING T where T.smartlet = 'Life-Pension Selector' GROUP BY T.trackingId
Basically, i got a table with tracking IDs, and a string representing the progresses ("100.0", "66.6", "33.3", ...). For each trackingId, i want to get the highest progress.
I Agree having Integers would make more sens, but it's a constraint I have to deal with. So i tried using the CAST. Also Attempted CAST(T.progress AS DECIMAL(10,5)) without success.
The same query without the CAST works just fine, but sorts alphanumerically ("66.6" > "100.0"). How should I tackle this problem?
Thanks for the help!
EDIT: Copying the same query directly inside SQL WorkBench works perfectly. Seems like Java.sql does not like my query for some reason.

Related

Criteria JPA - Call Postgres CAST function

I'm trying to call a Postgres function with Criteria but it's not working. I need to use the LIKE clause in a UUID field, so I need to convert into VARCHAR first.
The result I need:
SELECT * FROM my_table WHERE cast(uuid as varchar(36)) like '%1234%';
What I'm doing in Criteria:
final Path<UUID> uuidField = from.get("uuid");
var cast = cb.function("cast", String.class, uuidField, cb.literal("as varchar(36)"));
cb.like(cast, String.format("%%%s%%", stringValue));
The query which is being generated:
HQL: select generatedAlias0 from com.MyTable as generatedAlias0 where function('cast', generatedAlias0.uuid, 'as varchar(36)') like '%1234%' order by generatedAlias0.name asc
Error:
2022-08-08 18:38:48,549 WARN [io.ver.cor.imp.BlockedThreadChecker] (vertx-blocked-thread-checker) Thread Thread[vert.x-eventloop-thread-9,5,main] has been blocked for 2393 ms, time limit is 2000 ms: io.vertx.core.VertxException: Thread blocked
at antlr.ASTFactory.make(ASTFactory.java:342)
at antlr.ASTFactory.make(ASTFactory.java:352)
at org.hibernate.hql.internal.antlr.HqlBaseParser.jpaFunctionSyntax(HqlBaseParser.java:4633)
at org.hibernate.hql.internal.antlr.HqlBaseParser.primaryExpression(HqlBaseParser.java:1075)
The log is not so clear (I'm using Quarkus + Hibernate Reactive), but I suspect it crashed in database because the function('cast', generatedAlias0.uuid, 'as varchar(36)').
I think it should be something like: function('cast', generatedAlias0.uuid, as varchar(36)) (without quotes). But I don't know how to achieve this result to test my theory.
How can I call this CAST function?
After investigating some possible solutions (I'm avoiding to create custom database routines) I found something interesting in a answer from another question:
Currently JPA does not have APIs for replace() and cast(string as numeric). But you can use CriteriaBuilder.function(...) to create database native functions if database portability is not critical.
Source: JPA criteria builder: how to replace and cast a string to numeric in order-by?
I don't know if this is documented is some place, but assuming that there is no way to call CAST(x AS y) using Criteria, I tried a workaround to force the UUID to VARCHAR cast without using the probably unsupported CAST function.
I tested this direct SQL query to database:
SELECT * FROM my_table WHERE concat(uuid, '') like '%123%';
And it works. This CONCAT forces the cast to VARCHAR and the LIKE function does his job. Knowing this, I did:
final Path<UUID> uuidField = from.get("uuid");
var cast = cb.function("concat", String.class, uuidField, cb.literal(""));
cb.like(cast, String.format("%%%s%%", stringValue));
Worked perfectly. I hope this help someone else.
As #HaroldH said, it's a weird requirement, but happened in my project.

Spring named "IN" query producing error when given more than one entry

I'm using Spring's named queries to access my data and came upon an issue.
I have a rather long named query in my spring data repo:
List<LandscapeLocationEntity> findByIdCustomerIdAndIdProductGroupAndIdProductIdAndIdLocationIdInAndActiveFlag(String customerId, String ProductGroup, String productId, List<Integer> locationId, boolean activeFlag);
The query works perfectly fine as long as I provide a List<Integer> with only one entry. As soon as there is another entry it will throw a java.sql.SQLException: Borrow prepareStatement from pool failed.
As you can see in the screenshot, the call is different from the actual query (LOCATIONID(?,?) vs. LOCATIONID(?)).
I have a workaround which just executes the queries separately but that's not the way I want to have it in the long term.
If you need further information please tell me.
UPDATE:
To prove my point I removed all the other attributes and still get the same error:
Query is now: List<LandscapeLocationEntity> findByIdLocationIdIn(List<Integer> locations);

org.hibernate.NonUniqueResultException: query did not return a unique result: 2?

I have below code in my DAO:
String sql = "SELECT COUNT(*) FROM CustomerData " +
"WHERE custId = :custId AND deptId = :deptId";
Query query = session.createQuery(sql);
query.setParameter("custId", custId);
query.setParameter("deptId", deptId);
long count = (long) query.uniqueResult(); // ERROR THROWN HERE
Hibernate throws below exception at the marked line:
org.hibernate.NonUniqueResultException: query did not return a unique result:
I am not sure whats happening as count(*) will always return only one row.
Also when i run this query on db directly, it return result as 1. So whats the issue?
It seems like your query returns more than one result check the database. In documentation of query.uniqueResult() you can read:
Throws: org.hibernate.NonUniqueResultException - if there is more
than one matching result
If you want to avoid this error and still use unique result request, you can use this kind of workaround query.setMaxResults(1).uniqueResult();
Hibernate
Optional findTopByClientIdAndStatusOrderByCreateTimeDesc(Integer clientId, Integer status);
"findTop"!! The only one result!
I don't think other answers explained the key part: why "COUNT(*)" returns more than one result?
I just encountered the same issue today, and what I found out is that if you have another class extending the target mapped class (here "CustomerData"), Hibernate will do this magic.
Hope this will save some time for other unfortunate guys.
Generally This exception is thrown from Oracle when query result (which is stored in an Object in your case), can not be cast to the desired object.
for example when result is a
List<T>
and you're putting the result into a single T object.
In case of casting to long error, besides it is recommended to use wrapper classes so that all of your columns act the same, I guess a problem in transaction or query itself would cause this issue.
It means that the query you wrote returns more than one element(result) while your code expects a single result.
Received this error while doing otherwise correct hibernate queries. The issue was that when having a class extend another hibernate was counting both. This error can be "fixed" by adding a method to your repository class.
By overriding the class count you can manually determine the way this is counted.
#Override
public Integer count(Page<MyObject> page) {
// manual counting method here
}
I was using JPQL and wanted to return Map. In my case, the reason was that I wanted to get Map<String, String>, but had to expect List<Map<String, String>> :)
Check your table, where one entity occurring multiple time's.
I had the same error, with this data :
id
amount
clientid
createdate
expiredate
428
100
427
19/11/2021
19/12/2021
464
100
459
22/11/2021
22/12/2021
464
100
459
22/11/2021
22/12/2021
You see here clientid occurring two times with 464.
I solved it by deleting one row :
id
amount
clientid
createdate
expiredate
428
100
427
19/11/2021
19/12/2021
464
100
459
22/11/2021
22/12/2021
I have found the core of the problem:
result of SELECT COUNT(*) can be a list, if there is a GROUP BY in the query,
and sometimes Hibernate rewrite your HQL and put a GROUP BY into it, just for fun.
Basically your query returns more than one result set.
In API Docs uniqueResult() method says that
Convenience method to return a single instance that matches
the query, or null if the query returns no results
uniqueResult() method yield only single resultset
Could this exception be thrown during an unfinished transaction, where your application is attempting to create an entity with a duplicate field to the identifier you are using to try find a single entity?
In this case the new (duplicate) entity will not be visible in the database as the transaction won't have, and will never be committed to the db. The exception will still be thrown however.
Thought this might help to someone, it happens because "When the number of data queries is greater than 1".reference
As what Ian Wang said, I suspect you are using a repository from spring. And a few days ago you just copy past a class and forgot to delete it when it is finally unused. Check that repository, and see if there is multiple same class of table you use. The count is not the count of rows, but the count of the table problem.
This means that orm technology is not preprogrammed to give you which results you are looking for because there are too many of the same results in the database. for example If there is more than one same value in my database and I want to get it back, you will encounter the error you get with the select query.
For me the error is caused by
spring.jpa.hibernate.ddl-auto=update
in application.properties file replacing it with
spring.jpa.hibernate.ddl-auto=create solved the issue, but it still depends on your needs to decide which configuration you need in your project, for more insights on the topic check this.
First you must test the query list size; here a example:
long count;
if (query.list().size() > 0)
count=(long) criteria.list().get(0);
else
count=0;
return count;

IntelliJ IDEA code inspection: HQL custom dialect & registered functions

My question is about
using registered functions for date/time manipulations in Hibernate Query Language and
IntelliJ IDEA's code inspection for these registered functions in HQL.
I'm using Hibernate 4.2.5 with Java 7, and SQL Server 2008 R2 as the database, and IntelliJ IDEA 12.1.6.
In an HQL query I need to perform the TSQL DATEADD function - or the equivalent HQL date operation. This doesn't seem to exist.
Here's what I'd like to achieve:
update MyTable set startTime = GETDATE(), targetTime = DATEADD(HOUR, allocatedTime, GETDATE()), endTime = null where faultReport.faultReportId = :faultReportId and slaTypeId = :slaTypeId
Searching for answers online has been disappointingly no help, and the most common advice (like the comment seen here: https://stackoverflow.com/a/18150333/2753571) seems to be "don't use date manipulation in hql." I don't see how I can get around performing the operation in the SQL statement in the general case (e.g. when you want to update one column based on the value in another column in multiple rows).
In a similar fashion to the advice in this post: Date operations in HQL, I've subclassed a SQLServerDialect implementation and registered new functions:
registerFunction("get_date", new NoArgSQLFunction("GETDATE", StandardBasicTypes.TIMESTAMP)); // this function is a duplication of "current_timestamp" but is here for testing / illustration
registerFunction("add_hours", new VarArgsSQLFunction(TimestampType.INSTANCE, "DATEADD(HOUR,", ",", ")"));
and added this property to my persistence.xml:
<property name="hibernate.dialect" value="my.project.dialect.SqlServerDialectExtended" />
and then I'm testing with a simple (meaningless, admitted) query like this:
select x, get_date(), add_hours(1, get_date()) from MyTable x
The functions appear to be successfully registered, and that query seems to be working because the following SQL is generated and the results are correct:
select
faultrepor0_.FaultReportSLATrackingId as col_0_0_,
GETDATE() as col_1_0_,
DATEADD(HOUR,
1,
GETDATE()) as col_2_0_,
... etc.
But I now have this problem with IntelliJ IDEA: where get_date() is used in the HQL, the code inspection complains "<expression> expected, got ')'". This is marked as an error and the file is marked in red as a compilation failure.
Can someone can explain how to deal with this, please, or explain what a better approach is? Am I using the incorrect SQLFunction template (VarArgsSQLFunction)? If yes, which is the best one to use?
I'd like the usage of the registered function to not be marked as invalid in my IDE. Ideally, if someone can suggest a better way altogether than creating a new dialect subclass, that would be awesome.

list.get().method generate cast exception

I have written a code like this to fetch data from database using HQL:
Query qr=sess.createQuery("select i.contract_Vcode,i.installment_date from Installment i where i.vcode=:instalVcode").setParameter("instalVcode", installVcode);
qr.getNamedParameters();
List<Installment> li=null;
li=qr.list();
int coVcode=li.get(0).getContract_Vcode();
As I know the contract_Vcode is an integer. But when I want to run it, the followed error happens:
Error invoking Action using Hibernate Core Session / Transaction injection
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to information.Installment
More over when I want to see the exact element like this,
System.out.println("contract installDate is: "+li.get(0).getContract_Vcode());
Same error happens. How can I fix this?
You're currently only querying two parts of an installment. If you want to fetch the whole thing, I'd expect something like:
Query qr = sess.createQuery(
"select from Installment as i where i.vcode=:instalVcode")
.setParameter("instalVcode", installVcode);
If you fetch multiple properties (instead of whole entities), you just get back an Object[] for each row in the results.
So you could use your original query, but:
List<Object[]> li = qr.list();
int coVcode = (Integer) li.get(0)[0]; // 1st column of 1st row

Categories

Resources