QueryDSL Window functions - java

How can I write a query using window functions and selecting all fields in QueryDSL?
In the docs there is an example like this:
query.from(employee)
.list(SQLExpressions.rowNumber()
.over()
.partitionBy(employee.name)
.orderBy(employee.id));
but I need to generate a query like:
SELECT * FROM
(SELECT employee.name, employee.id, row_number()
over(partition BY employee.name
ORDER BY employee.id)
FROM employee) AS sub
WHERE row_number = 1
And is it possible to do it with JPAQuery?

JPAQuery supports only the expressivity of JPQL, so window functions are not supported, but paging should work using
query.from(employee).orderBy(employee.id).limit(1)
In case you need to use window functions and you need employee.name and employee.id out this should work
NumberExpression<Long> rowNumber = SQLExpressions.rowNumber()
.over()
.partitionBy(employee.name)
.orderBy(employee.id).as("rowNumber");
query.select(employee.name, employee.id)
.from(SQLExpressions.select(employee.name, employee.id, rowNumber)
.from(employee).as(employee))
.where(Expressions.numberPath(Long.class, "rowNumber").eq(1L))
.fetch();

As written by #timo Window functions (rank, row_number) are not supported by JPQL (JPA 2.1 version) and hence by JPAQuery (QueryDsl Jpa 4.1.4).
You can however rewrite your query so that is does not use rank over():
select a.* from employees a
where
(
select count(*) from employees b
where
a.department = b.department and
a.salary <= b.salary
) <= 10
order by salary DESC
This is supported by JPAQuery, it probably goes like this.
final BooleanBuilder rankFilterBuilder =
new BooleanBuilder(employee.department.eq(employee2.department));
rankFilterBuilder.and(employee.salary.loe(employee2.salary));
query.from(employee)
.where(JPAExpressions.selectFrom(employee2)
.where(rankFilterBuilder)
.select(employee2.count())
.loe(10))
.orderBy(employee.salary);

Related

QueryDSL order by subquery count

I want to implement the following SQL query with QueryDSL:
SELECT
*
FROM
a
ORDER BY (
SELECT
COUNT(*)
FROM
b
WHERE
b.a_id = a.id
AND b.c = 1) DESC
If I omit the criteria "b.c = 1", it's quite easy:
selectFrom(a).orderBy(a.bs.size().desc());
But I can't find a way (simple or not) to include a criteria in the subquery.
I want my QueryDSL query to return a List<A> and not Tuple, if possible.
Thanks in advance !

How to nest entity default output in another select query from statement using criteria builder in jpa 1.0.1?

I am implementing pagination using spring data and for sorting following query i want to prepare inside my specification.
SELECT *
FROM
(
SELECT distinct *
FROM
(
SELECT p.PROJECT_ID,
p.PROJECT_NAME,
p.PROJECT_TYPE
FROM PROJECT p
LEFT OUTER JOIN code c
ON p.codeId=c.ID
WHERE p.PROJECT_NAME IN ('test')
ORDER BY c.LABEL ASC
)
)
WHERE rownum <= 25;
but my specification is creating below script
SELECT *
FROM
(
SELECT distinct p.PROJECT_ID,
p.PROJECT_NAME,
p.PROJECT_TYPE
FROM PROJECT p
LEFT OUTER JOIN code c
ON p.codeId=c.ID
WHERE p.PROJECT_NAME IN ('test')
ORDER BY c.LABEL ASC
)
WHERE rownum <= 25;
Actually i am getting duplicate records after join so i am adding distinct function to fetch distinct records but as for order by clause to work the order by parameter should be present in select statement which is not possible in my case as in my entity it's not present neither i can change that.
So i just want to nest my select statement for project statement to another statement and there i want to put distinct as shown in the first script. I am very new to Spring jpa so any help would help.
Here is my specification.
public static Specification<Project> projectListSearchSpec(Set<String> deptNameList, ProjectSearchDto searchDTO) {
return new Specification<Project>() {
#Override
public Predicate toPredicate(Root<Project> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
query.distinct(true);
Predicate all = root.<Project>get("projectName").in(deptNameList);
return all;
}
};
}

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!

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 select using IN

Here is my select from the database:
SELECT * FROM testlogging.employees
where
EMPLOYEE_NO in (
select EMPLOYEES_EMPLOYEE_NO from testlogging.test_logging
where ID in (
select TEST_LOGGING_ID from testlogging.test_logging_detail
where APPROVAL_LEVELS_ID = '4'
)
)
How would i do this in JPA?
SELECT e FROM Employees e ???
If you're asking for the JPA INsyntax you would do this:
SELECT e FROM Employees e where e.employee_no IN :employeelist
as well ass
query.setParameter( "employeelist" , yourlist );
and of course build yourlist accordingly. If you don't really need to parameterize the inner queries, you can disregard this and just go the straight forward route.
Cheers,
Just in case you're using the JPA Criteria metamodel queries, the IN usage goes like this
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(pet.get(Pet_.color).in("brown", "black"));
as stated at http://docs.oracle.com/javaee/6/tutorial/doc/gjivm.html

Categories