Unable to run CASE WHEN for array in Spring Boot repository - sql

I am trying to run this
#Query(value = "SELECT t.*\n" +
"FROM tlm_trade t\n" +
"left join tlm_trade_nugget n\n" +
"on t.trade_nugget_id=n.id\n" +
"where \n" +
"(year(t.created_date) in (case when ?1 is null then year(t.created_date) else ?1 end))\n" +
";", nativeQuery = true)
List<TlmTrade> findByFilter(Set<Integer> year);
;
When I pass this as the argument
[2021,2020,2019]
Got this error instead
SQLException: Operand should contain 1 column(s)
Any idea what's wrong?

case when ... end is an expression, they evaluate to a single value.
In your example you are hoping that you could use a case expression to act as "dynamic sql". i.e. if ?1 is null, then insert the term "year(t.created_date)" but if ?1 is not null then insert ?1
You cannot do that.
It would make more sense to do this by branching before forming #Query, one branch for ?1 being null, and another which uses ?1
Also, avoid case expressions in where clauses, it is better to express filters in binary terms such as this, using parentheses where needed:
"where (?1 IS NULL AND year(t.created_date) = '2021' )\n"
?1 by the way will need to equal something, or be greater than something etc. ?1 by itself will not form a filtering condition.

Related

Using sub-select in FROM clause inside JPA #NamedQuery

In my app I need to use #NamedQuery to find the type of the most frequent operation assigned to specific account
#Entity
#Table(name="\"ACCOUNTOPERATION\"")
#NamedQuery(name="AccountOperation.findTypeOfMostFrequentOperation", query="" +
"SELECT ao.type from AccountOperation ao WHERE ao.account.id = ?1 " +
"GROUP BY ao.type HAVING COUNT(ao) = (" +
"SELECT MAX(typeCountQuery.typeCount) " +
"FROM (" +
"SELECT COUNT(aop) as typeCount " +
"FROM AccountOperation aop WHERE aop.account.id = ?1 GROUP BY aop.type" +
") as typeCountQuery" +
")"
)
public class AccountOperation {
#ManyToOne
private Account account;
private BigDecimal amount;
private OperationType type;
...
Right after FROM clause at '(' character, which begins typeCountQuery's body I'm getting
')', ',', GROUP, HAVING, IN, WHERE or identifier expected, got '('
I've read that JPA does not support sub-selects in the FROM clause, so is there any way to rewrite SQL code to still use it in #NamedQuery?
I'm using IntelliJ IDE with H2 DB and with eclipselink and javax.persistence in dependencies.
Link to source
In JPQL, you cannot use subqueries. To resolve this issue, you need to use some keywords like ALL, ANY, which work similiar.
So in your situation it could be:
#NamedQuery(name="AccountOperation.findTypeOfMostFrequentOperation", query="" +
"SELECT ao.type from AccountOperation ao WHERE ao.account.id = ?1 " +
"GROUP BY ao.type HAVING COUNT(ao) >= ALL (" +
"SELECT COUNT(aop) as typeCount " +
"FROM AccountOperation aop WHERE aop.account.id = ?1 GROUP BY aop.type)"
The type with a highest count returns the following query
select type
from AccountOperation
where id = ?
group by type
order by count(*) desc
fetch first 1 ROWS only
You should be anyway avare of the existence of ties, i.e. more types with the identical maximal count and should make some thought how to handle them.
I.e. in Oracle you may say fetch first 1 ROWS WITH TIES to get all the types with tha maximal count.

How to compare if BigDecimal value is inside a range in a query?

Lets say that I have to check in a query if a value is inside a range, and this value is BigDecimal in Java. The values inside the database are numbers(with two decimals). The ideia is above...but I don´t know the right way and to make it a little worst, I don´t have access to test the query apart. I´m using jpa extended repository, so probably I need to write my own query in this case.
#Query("SELECT c "
+ " FROM Taxes c "
+ " WHERE c.minOrderValue <= 'Mvalue' AND c.maxOrderValue >= 'Mvalue' "
)
Optional<TaxesRR> getTaxes(#Param("Mvalue") BigDecimal Mvalue);
That´s how it´s worked for me. Any other solution is still appreciated.
#Query("SELECT c "
+ " FROM ConjuntoTaxasRetencaoRapida c "
+ " WHERE c.valorMinimoPorteFaturamento <= ?1 "
+ " AND c.valorMaximoPorteFaturamento > ?2")
Optional<ConjuntoTaxasRetencaoRapida> obterTaxasRR(BigDecimal valorProjetadoMes, BigDecimal valorProjetadoMesConsolidado);

Sql Case expression in JPA criteria update

I have a named query :
"UPDATE student SET student.marks = " +
" CASE WHEN student.name in :" + nameListOne +
" THEN 10 ELSE marks " +
" END , student.class = 6 WHERE student.name in :" + namelistOneAndTwo
how can i achieve this using criteria update.
This is just a example i want to understand how case expression can be used in criteria update.
Might be easier just to have two updates. Not sure what "nameListOne" is, I'm assuming this is some parameter in a dynamic SQL query string.
UPDATE student
SET marks = 10
WHERE name IN nameListOne;
UPDATE student
SET class = 6
WHERE name IN nameListOneAndTwo;
There's some value in keeping things simple and intuitive.

How to transform SQL query into JPQL query?

I'm looking for how to transform the following query (SQL) into query JPQL;
SELECT * FROM equipements eq
LEFT JOIN check_lists checks
ON eq.id_equipements = checks.equipements_id
LEFT JOIN responses_check_lists resp
ON checks.id_check_lists = resp.check_lists_id
AND resp.missions_id = 15
AND eq.id_equipements = 1
ORDER BY checks.id_check_lists
I followed the documents on the internet but I do not get the correct transformation of my query in JPQL.
I know that the attributes of the query will be replaced by the attributes of the class.
I posted here to help me in transforming the SQL query.
Edit1:
#Query(
"SELECT r, checks, eq"
+ " FROM Equipements eq"
+ " LEFT JOIN CheckLists checks "
+ " ON eq.idEquipements = checks.equipements.idEquipements"
+ " LEFT JOIN ResponsesCheckLists r"
+ " ON checks.idCheckLists = r.CheckLts.idCheckLists"
+ " AND r.Respmission.idMission= :idmiss "
+ " AND eq.idEquipements= :idEqp"
+ " ORDER BY checks.idCheckLists ASC"
)
Error of Edit1:
Caused by: java.lang.IllegalStateException: No data type for node:
org.hibernate.hql.internal.ast.tree.IdentNode +-[IDENT] IdentNode:
'r' {originalText=r}
org.hibernate.hql.internal.ast.InvalidPathException: Invalid path:
'checks.idCheckLists'
Thank you in advance,
Analysing your SQL and without see the entities, your JPQL can be something like this:
SELECT eq FROM Equipements eq
LEFT JOIN eq.checks check
LEFT JOIN check.responses resp
LEFT JOIN resp.missions mission WITH mission.id = :idmiss
WHERE eq.id = :idEqp
ORDER BY check.id
But, to be something like this, you need to adjust the mapping of your entities (entity name, column names, etc).

A WHERE clause that always selects all records in a table

I'm looking to create a function that generates an SQL query, filtering the results by an expression given as a parameter (which will passed as a 'WHERE' clause). If the parameter is omitted, all results are returned.
In order to do this I can test for a null parameter and only build the where clause if parameter is given (where = (parameter != null) ? "" : "WHERE " + parameter). However, I was thinking is there an expression that I can default to that will always return all results. This way I don't need to test to see whether to include the WHERE keyword (where = "WHERE " + parameter).
I've intentionally not mentioned escaping the parameter to avoid injection. I won't forget this in my solution, I promise! :)
I usually use 1 = 1 for that.
(where = "WHERE 1 = 1 " + parameter)
In this case parameter should start with " AND " token.
You can initialize the parameter as TRUE or 1.