SQL Request if criteria is not null - java

I am trying to write a query that performs a search according to several criteria.
My current JPA request:
#Query("SELECT c FROM Client c " +
"INNER JOIN c.entite e " +
"WHERE e.numeroLicence in (:numerosLicence) " +
"AND (UPPER(c.nom) LIKE CONCAT('%',UPPER(:nom),'%') " +
"AND (c.prenom IS NOT NULL AND UPPER(c.prenom) LIKE CONCAT('%',UPPER(:prenom),'%')) " +
"AND (c.dateCreation IS NOT NULL AND c.dateCreation > :dateCreation) " +
"AND (c.dateCreation IS NOT NULL AND c.dateModification > :dateModification) " +
"AND (c.dateCreation IS NOT NULL AND c.dateSuppression > :dateSuppression)) ")
Page<Client> recherche(#Param("numerosLicence") ArrayList numerosLicence,
#Param("nom") String nom,
#Param("prenom") String prenom,
#Param("dateCreation") ZonedDateTime dateCreation,
#Param("dateModification") ZonedDateTime dateModification,
#Param("dateSuppression") ZonedDateTime dateSuppression,
Pageable pageable);
The problem is that it automatically excludes rows where a column contains NULL.
I'll need the selection to be done on columns with data only, it will not try to execute the clause if the field value is NULL
For example, if I have a row whose firstname column is NULL, then this line is automatically excluded from the result whereas I would like it not to test this column if it is NULL
Do you have an idea?
I'm looking for a solution to avoid creating as many queries as possible combination

Sounds like you should use OR instead of AND:
c.dateCreation IS NULL
OR c.dateCreation > :dateCreation

Related

Ignoring condition if the parameter is null in Spring Data JPA

I am currently developing the search and filtering feature of my project. I am trying to retrieve data with this Request body:
{
"researchers": [
"Jhon Doe"
],
"unit": null,
"agency":null,
"date": null,
"status": null,
"budget": null
}
and below is the method from the ReasearchRepository that retrieves this data:
#Query("select r from Research r " +
"left join r.fundingAgencies fundingAgencies " +
"left join r.researchers researchers " +
"where (:budgetStart is null or :budgetEnd is null or r.budget between :budgetStart and :budgetEnd )" +
"and (:startDate is null or r.startDate >= :startDate) " +
"and (:endDate is null or r.endDate <= :endDate) " +
"and (:agencyNames is null or fundingAgencies.agencyName in :agencyNames) " +
"and (:unitNames is null or r.deliveryUnit.unitName in :unitNames )" +
"and (:names is null or researchers.name in :names ) " +
"and (:researchStatuses is null or r.researchStatus in :researchStatuses)")
List<Research> findAdvanced( #Param("budgetStart") Double budgetStart,
#Param("budgetEnd") Double budgetEnd,
#Param("startDate") LocalDate startDate,
#Param("endDate") LocalDate endDate,
#Param("agencyNames") Collection<String> agencyNames,
#Param("unitNames") Collection<String> unitNames,
#Param("names") Collection<String> names,
#Param("researchStatuses") Collection<ResearchStatus> researchStatuses);
My problem is when I'm trying to find data from given values in the request, it returns an empty list [] even though it exists in the database. What I want to achieve is that if the parameter is null, it will ignore a specific condition in the query and will still return data.
I just followed the article from Baeldung.
I also find another article about using Criteria API, but it will take a lot of time for me to understand that. My project is a bit rush.
TIA
I seems like a good case to use Specifications.
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/

JPA : Use of list in where clause and Case statement together - Is there a way to loop through?

I am using JPA-Hibernate in our application and I am working with a query like :
#Query(
value = "ReportDTO(report) FROM Report report " +
"JOIN p.clientFile cf " +
"JOIN cf.client cl " +
"WHERE report.active = TRUE " +
"AND :companyKey = CASE WHEN report.companyKey IS NOT NULL " +
"THEN report.companyKey " +
"ELSE cl.companyKey " +
"END " +
"ORDER BY report.publishedDate DESC",
countQuery = “..”
)
#NonNull
Page<TagReportDTO> findAll(#NonNull Pageable pageable, #Param("companyKey") String companyKey);
when the "companyKey" was a single value, it worked. Now, I need to change this findAll method to accept a list of company keys. So it should like like ( after the change) :
#NonNull
Page<TagReportDTO> findAll(#NonNull Pageable pageable, #Param("companyKeys") List<String> companyKeys);
Now I am getting hard time to accommodate the list of objects or companyKeys (instead of :companyKey) in the query where the the case statement will be applicable to each item in the list. Is there a way I can loop through ?
Did you try using IN operator? Like this:
"AND (CASE WHEN report.companyKey IS NOT NULL " +
"THEN report.companyKey " +
"ELSE cl.companyKey " +
"END) IN :companyKeys "

TEXT column: Argument data type text is invalid for argument 1 of lower function

I currently have a repo method which is acting as a filter with pagination:
Repo:
#Query("SELECT e FROM DeTest e " +
"WHERE e.deactivationTime = '9999-12-31 00:00:00.000' " +
"AND (:name is null OR LOWER (e.name) LIKE LOWER ('%' + :name+ '%')) " +
"AND (:description is null OR LOWER (e.description) LIKE LOWER ('%' + :description + '%')) " +
"AND (:theProblem is null OR LOWER (e.theProblem ) LIKE LOWER ('%' + :theProblem + '%')) "
)
So as shown here, I have it so when you enter a value it will change it ensuring that both uppercase values and lowercase values are displayed. However, when adding LOWER to the 'theProblem' column, it produces the error in the title:
Argument data type text is invalid for argument 1 of lower function
My datatype for that particular column is text, and therefore, I think the culprit of the issue. However, due to the db layout I need it to be a text. Therefore, is there anyway I could convert/cast it in the repo method for when it's called?
Column:
#Column(name = "the_problem", columnDefinition = "TEXT") // text rather than varchar
private String theProblem;
Thank you.

How to skip #Param in #Query if is null or empty in Spring Data JPA

#Query(value = "Select f from Documents f " +
"RIGHT JOIN f.documentStatus ds " +
"where f.billingAccount.accountId in :billingAccountIdList " +
" and ds.statusCode in :paymentStatuses" +
" and f.paymentDate < :paymentDate")
List<FinancialDocumentEntity> getFinancialDocumentsOverdue(#Param("billingAccountIdList")List<String> billingAccountIdList,
#Param("paymentStatuses") List<String> paymentStatuses,
#Param("paymentDate") Date paymentDate);
I have query like above. It is possible to skip searching param for example #Param("paymentStatuses") in query method if is null or is empty ?
Try changing
" and ds.statusCode in :paymentStatuses"
into
" and (:paymentStatuses is null or ds.statusCode in :paymentStatuses)"
Try changing
" and ds.statusCode in :paymentStatuses"
into
" and (COALESCE(:paymentStatuses, null) is null or ds.statusCode in :paymentStatuses)"
This solution will work for the empty list, null list, and a list with items 1 or more.

Query id return type

I use spring data. I want to get some contracts from DB. So I create two queries. In first I get contracts id that I need, in second I get contract by this id.
First query in Repository.class
#Query(nativeQuery = true, value =
"select id from (" +
"select contract.id, max(invoice.period_to) " +
"from public.invoice " +
"join public.contract on contract.id = invoice.contract_id " +
"where invoice.period_to <= '2017-10-20' " +
"AND contract.close_type IS NULL " +
"AND contract.payment_type != 'TRIAL' " +
"group by contract.id" +
") foo ")
List<Long> findContractsIdForInvoicesCreation();
ServiceJPA.class
List<Long> contractsId = ContractRepository.findContractsIdForInvoicesCreation();
List<Contract> contracts = contractRepository.findAll(contractsId);
But in last line above I have an error.
java.lang.IllegalArgumentException: Parameter value element [2] did not match expected type [java.lang.Long (n/a)]
If I simply create
List<Long> contractsIdL = new ArrayList<>();
contractsIdL.add(2L);
contractsIdL.add(3L);
contractsIdL.add(4L);
List<Contract> contracts = contractRepository.findAll(contractsId);
All works fine. Cant figure out what is wrong. In which type do first query return id?
p.s. id type in DB is bigint
p.p.s. I checked first query with System.out.println - it seems to return correct numbers.
I think the issue is with ContractRepository.findContractsIdForInvoicesCreation();
I think it doesn't return List<Long> as you expected

Categories