JPA NamedQueries problem with nested logical operator - java

I have the following Problem. I want to filter on a column in my table to either be true or if false then only give me the entries with a date greater than xxx. So basicly return me every Customer that is a valid customer and return alle Customers that are not valid and have a activationDate greater then 3.5 years.
name
is_customer
activation_date
Pete
True
2021.02.02
Sam
False
2021.02.02
I tried the query inside my psql console and there everything is working fine. But when im trying to adapt it to be used with #NamedQueries in my JPA Entity the query cant be validated (neither in Intellij nor while running the code).
Query in Postgres (WORKING FINE):
SELECT * FROM customer c
WHERE (c.is_customer = true) OR (c.is_customer = false AND c.activation_date > CURRENT_DATE + INTERVAL '3.5 years');
Query in Java (NOT WORKING):
#NamedQuery(name = CustomerBE.NAMED_QUERY,
query = "SELECT c FROM CustomerBE c "
+ "WHERE (c.isCustomer= true) OR (c.isCustomer= false AND c.activationDate > CURRENT_DATE + INTERVAL '3.5 years')"
)
Intellij Error: '(', <expression> or identifier expected, got '('
JPQL Error:
Exception Description: Syntax error parsing [SELECT c FROM CustomerBE c WHERE (c.isCustomer= true) OR (c.isCustomer= false AND c.activationDate > CURRENT_DATE + INTERVAL '3.5 years'].
[41, 297] The expression is not a valid conditional expression.
[297, 298] The query contains a malformed ending
I already tried adaption the bracket placement.
Did someone maybe have a simmilar problem or a workaround solution for me?

You probably need to put a space before the WHERE clause or else your string will not be a valid JPQL:
"SELECT c FROM CustomerBE cWHERE (c.isCustomer= true) O ..."
I'm not sure if this is the problem you reported, but it is also a problem to be fixed.

Ok fixed it now. The Problem was the postgre Part "CURRENT_DATE + INTERVAL '3.5 years'" had to substitute it with :filterDate and set it through the parameter.

Related

Cannot return boolean using JPQL in Spring

I have the following JPQL query in my repository and when I run its SQL version (our database is PostgreSQL), it works properly. However, when I run this JPQL, it returns only the records that has True value. I think the problem may be related to JPQL and wanted to ask. So, is there any problem regarding to this query?
#Query("SELECT p.uuid as uid, " +
"CASE WHEN m.uuid IS NOT NULL THEN true ELSE false END as d FROM Product p " +
"LEFT JOIN Menu m on m.productUuid = p.uuid ")
List<ProductMenu> findAllProduct();

HQL : The column must appear in GROUP BY or in Select

I've this query with WrappedBean :
buffer.append("SELECT new myPackage.WrappedBean(E.debitant.id, E.dateCalcul, E.verse, E.incidenceReprise, E.soldeSoumission) ");
buffer.append("FROM " + getEntityClassName() + " E ");
buffer.append("LEFT JOIN E.debitant DT ");
buffer.append("WHERE E.debitant.id = :idDebitant ");
buffer.append("AND YEAR(E.dateCalcul) = :year ");
buffer.append("GROUP BY E.debitant.id");
hqlQuery = session.createQuery(buffer.toString());
hqlQuery.setInteger("idDebitant", idDebitant);
hqlQuery.setInteger("year", year);
I've created WrappedBean for returning somme columns and for using Group BY.
When i try to execute it, i obtain this error :
org.postgresql.util.PSQLException: ERREUR: The column « complement0_.date_calcul » must appear in GROUP BY clause or must be used in Select (i translate the error from french)
My POSTGRES query doesnt contain date_calcul in Group BY.
Another problem, in my query i've also this :
SUM(CASE WHEN YEAR(dateCalcul)=#PECAnnee AND verse>0 THEN verse ELSE 0 END)
I know in HQL, we cant do case when in select, for this reason, i dont add SUM to column verse
What i've forgot ?
My POSTGRES query doesnt contain date_calcul in Group BY
That's the problem and what Postgres is complaining about. Why isn't it in the SQL query? Because it isn't in the HQL query. Any column that is selected without the use of some aggregate method like sum(), min(), max() etc. needs to be part of the GROUP BY clause since otherwise the DB doesn't know how to handle multiple values/conflicts.
As an example, what value of E.dateCalcul should be passed to WrappedBean if there are multiple debitors (debitants) (which is most probably the case since otherwise there wouldn't be any need for the GROUP BY clause)?
So to fix this either use
GROUP BY E.debitant.id, E.dateCalcul, E.verse, E.incidenceReprise, E.soldeSoumission
or use aggregate functions, e.g.
WrappedBean(E.debitant.id, max(E.dateCalcul), min(E.verse), max(E.incidenceReprise), sum(E.soldeSoumission))

Spring data repository sends null as bytea to PostgreSQL database

After switching from MySQL to PostgreSQL I found out that my SQL query (#Query in spring data repository interface) does not work anymore. The issue is caused by null value being sent as bytea and I'm getting following exception:
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: bigint = bytea
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Repository with #Query:
public interface WineRepository extends PagingAndSortingRepository<Wine, Long> {
#Query(value = "SELECT * FROM WINE w WHERE (?1 IS NULL OR w.id = ?1)", nativeQuery = true)
Wine simpleTest(Long id);
}
Simple test:
LOGGER.warn("test1: {}", wineRepository.simpleTest(1L)); //ok
LOGGER.warn("test2: {}", wineRepository.simpleTest(null)); //PSQLException
In the real case I have multiple parameters which can be null and I would prefer not checking them in java code but sending them to sql query. I have checked questions here on stackoverflow but found none with a good answer especially for spring data repository #query annotation.
What is a correct way of handling null values with PostgreSQL? Or do you have any hints how to fix my approach? Thanks!
Update:
Issue seems to be related to nativeQuery = true, when value is false, null values work as expected. So the question is whether it is possible to make it function even with nativeQuery enabled.
Try this.
SELECT *
FROM WINE w
WHERE ?1 IS NULL OR w.id = CAST(CAST(?1 AS TEXT) AS BIGINT)
It satisfies the type checker and should have the same properties as the original query. CAST is not a big performance hit if it happens on a constant value rather than a value from a database row.
You are trying to check whether a Java null is equal to Postgres NULL which I think is not necessary. You can rewrite as following and avoid sending null to the simpleTest function at all.
#Query(value = "SELECT * FROM WINE w WHERE (w.id IS NULL OR w.id = ?1)", nativeQuery = true)
Wine simpleTest(Long id);
I had a similar issue in an #Query where a Long was being interpreted by Postgres as a bytea. The solution for me was to unbox the #Param...by passing a long value, Postgres correctly interpreted the value as a bigint
I know it is an old issue, but you should be able to fix that bay casting the java value. Something like:
public interface WineRepository extends PagingAndSortingRepository<Wine, Long> {
#Query(value = "SELECT * FROM WINE w WHERE (?1\\:\\:bigint IS NULL OR w.id = ?1\\:\\:bigint)", nativeQuery = true)
Wine simpleTest(Long id);

Concatenation in JPA 1.0

I am facing an issue while trying to concatenate column values in JPA 1.0 named query :
SELECT aum.id.pin, aum.id.planNBR, aum.id.subPlanNBR, AVG(aum.aumAmount)
FROM AUMBalanceDO aum
WHERE " + "CONCAT(aum.id.pin,aum.id.planNBR,aum.id.subPlanNBR) NOT IN (
SELECT CONCAT(PAP.pin,edo.planNBR,edo.subPlanNBR)
FROM " + "ParticipantAdvicePortfolioDO PAP, EnrollmentDO edo
WHERE PAP.userID = edo.userID AND edo.status ='E'
AND edo.startDT < :endDate " + "
AND (edo.endDT > :endDate OR edo.endDT IS NULL)
)
AND aum.id.priceDate
BETWEEN :startDate AND :endDate GROUP BY aum.id.pin, " + "aum.id.planNBR, aum.id.subPlanNBR"
I am getting the below exception while trying to run the query,
unexpected token [concat]
As per the error its clear that in JPA 1.0 we dont have concat function is there any other alternative way to achieve this?
Plain SQL Native concatenation '||' seems to be working just fine in JPQL of JPA 1.0 spec (JPA is provided here by Hibernate 3.3.x and RDBMS is Oracle 11).
SELECT NEW PartSearchView(partIssue.id, partIssue.stage || partIssue.issue)
FROM PartIssue partIssue INNER JOIN partIssue.part part
The signature of constructor used above is:
PartSearchView(Long id, String stageIssue)
I got a nice concatenation of both stage and issue fed into PartSearchView constructor.
Hope this helps!
Cheers!

CASE statement in HQL or Criteria

derived from this question, is it possible to use HQL or Criteria for the following SQL statement:
SELECT
e.type,
count(e),
count(d),
count (case when gender = 'male' then 1 else NULL end) AS NumberOfMaleEmployees
from Department d
JOIN d.employees e
WHERE e.dead = 'maybe'
GROUP BY e.type
Although google comes up with a few hits that state HQL supports CASE statements, Hibernate 3.6.6 fails with a
QuerySyntaxException: unexpected token: CASE
when I create the query above on an EntityManager instance.
How much of a bad idea is it, to create another query for every e.type to determine the number of males manually, e.g. for every e.type
SELECT
count(e),
from Department d
JOIN d.employees e
WHERE e.dead = 'maybe', e.type = ugly
Since there could be quite a few types, this is potentially slow. I'd like the database to do the work for me.
Well, it seems, case statements are supported:
http://docs.jboss.org/hibernate/core/3.5/reference/en/html/queryhql.html
They just don't seem to work within count(). An alternative would be using sum(case when... then 1 else 0 end) instead

Categories

Resources