How to use optional WHERE clause in the SQL? - java

I'm trying to fetch the records in a single sql. I would like to use optional WHERE clause in order to do that.
This is what I tried
#Query(value = "select * from Products p where type = 'L' and active =
1 and ?1 is null or p.pNum =?1", nativeQuery = true)
public List<Products> findAllParties(String productNumber);
This did not work.
I would like to bring all the records when the parameter is empty else would like to bring only the specified product.
How do I do that? Thanks in advance.

select * from Products p where req_param is null or ( type='L' and active=1)
Since if req_param is null it will be true for all the rows therefore will bring all records.
if req_param is not empty/null condition "req_param is null" will be false and
rows will be returned only basis upon "( type='L' and active=1)"

Make 2 separate methods
#Query(value = "select * from Products p where type = 'L' and active =
1 and ?1 is null or p.pNum =?1", nativeQuery = true)
public List<Products> findAllParties(String productNumber);
#Query(value = "select * from Products p ", nativeQuery = true)
public List<Products> findAllParties();

If you want conditionally built queries, use JPA's Criteria API for that or Spring's Specifications API .

Related

Using JPA native query with zero or more parameters

Goal: I am trying to build query via JPA which returns a list of locations, nearest to the coordinates passed to the query. The ability to apply filter(s), sort and paginate on the query are required. The following native SQL query is what I came come up with so far:
SELECT s.*
,sqrt(power(abs(:latitude-g.latitude),2)+power(abs(:longitude-g.longitude),2)) as d
FROM geolocations g
INNER JOIN salons s
ON g.zip=s.zip
WHERE LOWER(s.salon_name) LIKE LOWER(CONCAT('%',:q,'%'))
ORDER BY d asc limit
:pageSize offset :offset
Paganation, some sorting, and location based search are all working, but I cannot get filtering to work.
The filter requirement states that a user must also be able to filter search results(0 or more filters) by fields, like owner,state,zip... I want to use something like querydsl or the JPA Specification object to build a small query language but I cannot build out a working implementation given the fact that I am using a native query. I am looking for any recommendations on how I could implement the field filters into my existing repository.
Here is my entire repository:
public interface SalonRepository extends JpaRepository<Salon,String>, JpaSpecificationExecutor<Salon>{
#Query("select s from Salon s where s.city = :city and s.state = :state")
Page<Salon> findByCity(#Param("state")String state,#Param("city")String city,Pageable pageable);
#Query("select s from Salon s where s.salonName = :name")
Page<Salon> findByName(#Param("name")String name,Pageable pageable);
//THIS IS THE ONE I WANT TO ADD THE USER DEFINED FILTERS TO
#Query(value = "select s.*,sqrt(power(abs(:latitude-g.latitude),2)+power(abs(:longitude-g.longitude),2)) as d from geolocations g inner join salons s on g.zip=s.zip where LOWER(s.salon_name) like LOWER(CONCAT('%',:q,'%')) order by d asc limit :pageSize offset :offset", nativeQuery = true)
List<Salon> findNearest(#Param("latitude")float latitude,#Param("longitude")float longitude,#Param("q")String query,#Param("pageSize")int pageSize,#Param("offset") int offset);
#Query(value = "select sqrt(power(abs(:latitude-g.latitude),2)+power(abs(:longitude-g.longitude),2)) as d from geolocations g inner join salons s on g.zip=s.zip where LOWER(s.salon_name) like LOWER(CONCAT('%',:q,'%')) order by d asc", nativeQuery = true)
List<Float> findNearestInt(#Param("latitude")float latitude,#Param("longitude")float longitude,#Param("q")String query);
#Query("select s from Salon s where lower(s.salonName) like LOWER(CONCAT('%',:salonName,'%'))")
Page<Salon> findAll(#Param("salonName")String salonName,Pageable pageable);
}
After hours of searching, I am fairly certain I am on the wrong track given the lack of information I've uncovered.
Any and all help is appreciated!

Multiple column IN clause spring data jpa

Is it possible to have multiple columns in IN clause?
#Query(nativeQuery = true, value = "select * from table where (column1, column2) in (:column1, :column2)")
List<Table> findByColumn1Column2In(#Param("column1") List<BigDecimal> column1, #Param("column2") List<BigDecimal> column2);`
Expecting a query like this:
select * from table where (column1, column2) in ((1,2), (3,4), (5,6))
Since JPA doesn't support multi-columns IN clauses I overcome this by using SQL CONCAT function on the DB values, and of course, on the supplied range values, as follows:
first, create the range we looking for:
List<String> columns;
for (i=0, i<column1.size(), i++){
columns.add(column1.get(i) + '-' + column2.get(i));
}
Modify the query:
#Query(nativeQuery = true,
value = "select * from table where CONCAT(column1, '-', column2) in (:columns)")
List<Table> findByColumn1Column2In(#Param("columns") List<String> columns);
And there you nail that :-)
Multiple column with IN clause in not yet supported by Spring data. You can use #Query annotation for custom query as below:
#Query( "select o from MyObject o where id in :ids" )
List findByIds(#Param("ids") List inventoryIdList);
Yes, It is possible to have multiple "In" clause in a method.
Using spring data jpa and spring boot we can achieve this as below:
For your case you can just write the below method in your repository and it would work fine.
List<Table> findByColumn1InAndColumn2In(List<BigDecimal> column1,List<BigDecimal> column2);

how to write with clause using criteria in hibernate

I have a query where i used WITH clause to generate results.
WITH employee AS (SELECT * FROM Employees)
SELECT * FROM employee WHERE ID < 20
UNION ALL
SELECT * FROM employee WHERE Sex = 'M'
Could you please any one let me know how to write this query in hibernate using criteria specially when with clause present in query.
First, you've dramatically over-complicated your SQL. Here's how your query should look in pure SQL:
SELECT * FROM Employees WHERE ID < 20 or Sex = 'M'
Next, assuming you have a Hibernate entity (let's call it Employee.java for now), your HQL equivalent would be:
from Employee e where e.id < 20 or e.sex = 'M'
To do it with a Criteria, you'd do the following:
final Criteria criteria = getSession().createCriteria(Employee.class);
criteria.add(Restrictions.or(
Restrictions.lt("id", 20),
Restrictions.eq("sex", "M")
)
);
criteria.list();

JPA Native query get a Single Object

How can i get a single object by using JPA Native query. I did some researches but all give an answer is use "getSingleResult", however it didn't return what i want to get. For example, what should i do if i want to get a count of table in my database and fetch it into a Integer.
This code below shows how i get this by using Sessison hibernate:
int check = Integer.parseInt((String) sessionF.createSQLQuery("select to_char(count(*)) as count from user_tables where table_name upper('TEST')").uniqueResult());
And what i hope to be fine in JPA:
int check = Integer.parseInt((String) getEntityManager().createNativeQuery("select to_char(count(*)) as count from user_tables where table_name upper('TEST')").getSingleResult());
Obviously, the code doesn't return what i want. Therefore, please help me to cope with this problem. Thank you !
With JPA you need to do like following
int num = ((Number)this.entityManager.createNativeQuery("select count(*) from your_table_name")
.getSingleResult()).intValue();
edited :
String name = this.entityManager.createNativeQuery("select t.name from your_table_name t limit 1").getSingleResult().toString();
you will got count with num object
Hope its will help to you.
In case of native query with multiple select expressions returns an Object[] (or List<Object[]>).
you can use below example code as per your requirement .
Query q = em.createNativeQuery("SELECT id,name FROM user WHERE id = ?1");
q.setParameter(1, userId);
Object[] result = (Object[])q.getSingleResult();
String id= result[0];
int name = result[1];
You might need to typecast the result Array values.
This may help someone.
To get a single object you can choose either of the below:
Method 1:
Query theQuery = entityManager.createNativeQuery("SELECT * from yourTable where yourTableId = (Select MAX(yourTableId) from yourTable where empId = ?1 and instId = ?2 GROUP BY empId,instId)",YourTableEntity.class);
theQuery.setParameter(1, empId);
theQuery.setParameter(2, instId);
System.out.println(theQuery.getSingleResult());
Method 2:
Query theQuery = entityManager.createNativeQuery("SELECT * from yourTable where empId = ?1 and instId = ?2 order by yourTableId DESC");
theQuery.setParameter(1, empId);
theQuery.setParameter(2, instId);
theQuery.setMaxResults(1); //Use if it makes good impact in complexity
System.out.println(theQuery.getResultList().get(0));
NOTE: For simplicity sake I just printed it. You may need to typecast.
Check if the time taken by method 1 or method 2 works better for you.

Join fetch: "query specified join fetching, but the owner of the fetched association was not present in the select list"

I have a following code:
public class ValueDAO implements BusinessObject<Long> {
private Long id;
private String code;
private ClassDAO classDAO ;
....
}
public List<String> getCodesByCodeClass(Long classId) {
String select = "select distinct val.code from ValueDAO val left " +
"join fetch val.classDAO ";
String where = "where val.classDAO.id = ? order by val.code";
return getHibernateTemplate().find(select + where, classId);
}
It raises an exception:
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list
In the result I wan to get only codes.
join fetch val.classDAO.b means "when fetching val, also fetch the classDAO linked to the val". But your query doesn't fetch val. It fetches val.code only. So the fetch makes no sense. Just remove it, and everything will be fine:
select distinct val.code from ValueDAO val
left join val.classDAO classDAO
where classDAO.id = ?
order by val.code
Some notes, though:
doing a left join and then adding a retriction like classDAO.id = ? means that the join is in fact an inner join (since classDAO can't be null and have the given ID at the same time)
naming your entities XxxDAO is very confusing. DAOs and entities are not the same thing at all.
Given the above, the query can be rewritten as
select distinct val.code from ValueDAO val
where val.classDAO.id = ?
order by val.code

Categories