how to write with clause using criteria in hibernate - java

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();

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 use optional WHERE clause in the SQL?

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 .

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);

QueryDSL Window functions

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);

Hibernate Criteria to find Duplicates

I want to get the duplicate entries. I want to use the query as criteria, for this i am using the below code.
SELECT * from A
WHERE field in (
SELECT field from A
GROUP BY field HAVING COUNT(field) > 1
);
The Hibernate mapping is like
#Entity
class A{
...
private String field;
...
}
How can I get list of A that have duplication in 'field' column?
You can pretty much translate your query one to one to HQL (warning: untested).
select A
from A a
where a.field in (
select ai.field
from A ai
group by ai.field -- assumes that by f you mean field
having count(a1.field) > 1
)
My own answer according prompted Anthony Accioly
final Criteria searchCriteria = session.createCriteria(A.class);
...
final DetachedCriteria d1 = DetachedCriteria.forClass(A.class);
d1.setProjection(Projections.count("field"));
d1.add(Restrictions.eqProperty("field", "AA.field"));
final DetachedCriteria d2 = DetachedCriteria.forClass(A.class, "AA");
d2.setProjection(Projections.projectionList()
.add(Projections.groupProperty("field")));
d2.add(Subqueries.lt(1L, d1));
criteria.add(Property.forName("field").in(d2));

Categories