Is this query possible using Criteria or DetachedCriteria Hibernate - java

The question is simple can this query be done in Hibernate using Criteria or DetachedCriteria? i guess not but i wanted to do this question maybe exist a workaround.
SELECT
COLUMNS
FROM table
WHERE id not in (
SELECT * FROM (
SELECT id
FROM table
WHERE
SOMECONDITIONS
ORDER BY timestamp desc limit 0, 15
)
as t);
I will mark the answer by #Dean Clark as correct but another question arises is the following
where can i find the findByCriteria from SessionFactory we are not using Spring

To exactly match you query, you really need to do it with 2 steps, but I'd avoid this if possible:
final Criteria innerCriteria = getSession().createCriteria(YourEntity.class);
// SOME CONDITIONS
innerCriteria.add(Restrictions.eq("someColumn", "someValue"));
innerCriteria.addOrder(Order.desc("timestamp"));
innerCriteria.setMaxResults(15);
innerCriteria.setProjection(Projections.id());
List<YourIdClass> ids = innerCriteria.list();
final Criteria criteria = getSession().createCriteria(YourEntity.class);
criteria.add(Restrictions.not(Restrictions.in("id", ids)));
List<YourEntity> results = criteria.list();
Would the objects you're trying to identify have the same "SOMECONDITIONS"? If so, this would functionally accomplish what you're looking for:
final DetachedCriteria criteria = DetachedCriteria.forClass(YourEntity.class);
// SOME CONDITIONS
criteria.add(Restrictions.eq("someColumn", "someValue"));
criteria.addOrder(Order.desc("timestamp"));
getHibernateTemplate().findByCriteria(criteria, 16, 9999999);

Related

how to create predicate of the jpa specification or criteria query for the below query

I am trying to create JPA specification for with filter data between two dates date1 and date2, I tried to create through subquery but no luck as of now, please help if possible.
I am trying to create the specification for the below SQL query,
select
* from
subscription sub join (
select subscription_id,
max(output_date) as max_output_date
from
subscription_package
where
package_status = 'COMPLETE'
group by
subscription_id) sp on
sub.id = sp.subscription_id where
max_output_date between 'date1' and 'date2'
Below is the query created in JPA:
Subquery<Date> datequery = query
.subquery(Date.class);
Root<SubscriptionPackage> dateRoot = datequery
.from(SubscriptionPackage.class);
Subquery<SubscriptionPackage> subquery = query
.subquery(SubscriptionPackage.class);
Root<SubscriptionPackage> subqueryRoot = subquery
.from(SubscriptionPackage.class);
datequery.select(criteriaBuilder
.greatest(subqueryRoot.<Date>get("outputDate")));
datequery.where(criteriaBuilder.equal(subqueryRoot.get("PackageStatus"),
'COMPLETE'));
datequery.groupBy(subqueryRoot.get("subscription"));
not able to use the result from date query for the comparison like
query.where(criteriaBuilder.between(datequery., outFrom, outTo));
I don't know why you are using Subquery and you can use simple Spring data jpa with joins get your desire result.
Please check these examples
For date comparison:
criteriaBuilder.between(root.get("createdDate"), fromDate, toDate));

JPA CriteriaQuery with LEAST and GREATEST functions

I am have a problem where i need to join two tables using the LEAST and GREATEST functions, but using JPA CriteriaQuery. Here is the SQL that i am trying to duplicate...
select * from TABLE_A a
inner join TABLE_X x on
(
a.COL_1 = least(x.COL_Y, x.COL_Z)
and
a.COL_2 = greatest(x.COL_Y, x.COL_Z)
);
I have looked at CriteriaBuilder.least(..) and greatest(..), but am having a difficult time trying to understand how to create the Expression<T> to pass to either function.
The simplest way to compare two columns and get the least/greatest value is to use the CASE statement.
In JPQL, the query would look like
select a from EntityA a join a.entityXList x
where a.numValueA=CASE WHEN x.numValueY <= x.numValueZ THEN x.numValueY ELSE x.numValueZ END
and a.numValueB=CASE WHEN x.numValueY >= x.numValueZ THEN x.numValueY ELSE x.numValueZ END
You can code the equivalent using CriteriaBuilder.selectCase() but I've never been a big fan of CriteriaBuilder. If requirements forces you to use CriteriaBuilder then please let me know and I can try to code the equivalent.
CriteriaBuilder least/greatest is meant to get the min/max value of all the entries in one column. Let's say you want to get the Entity that had the alphabetically greatest String name. The code would look like
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery(EntityX.class);
Root<EntityX> root = query.from(EntityX.class);
Subquery<String> maxSubQuery = query.subquery(String.class);
Root<EntityX> fromEntityX = maxSubQuery.from(EntityX.class);
maxSubQuery.select(cb.greatest(fromEntityX.get(EntityX_.nameX)));
query.where(cb.equal(root.get(EntityX_.nameX), maxSubQuery));
I created a sample Spring Data JPA app that demonstrates these JPA examples at
https://github.com/juttayaya/stackoverflow/tree/master/JpaQueryTest
It turns out that CriteriaBuilder does support calling LEAST and GREATEST as non-aggregate functions, and can be accessed by using the CriteriaBuilder.function(..), as shown here:
Predicate greatestPred = cb.equal(pathA.get(TableA_.col2),
cb.function("greatest", String.class,
pathX.get(TableX_.colY), pathX.get(TableX_.colZ)));

hibernate nested query HQL/criteria

I'm trying to express a somewhat complex query in hibernate either with HQL or Criteria but I didn't find the way. I'm aware that cannot expect the orm to solve everything but I'm not such an expert in hibernate and I got so closed that I'm hoping that I'm missing something silly.
I've been looking in SO for questions and there is this one and nobody answered except the author, who gave up and posted a solution using plain SQL. So maybe I'm wasting my time and I should do the same. And maybe you consider this is a duplicate... I'm not sure.
The query I'm trying to build is
select * from user_rank
where user_id in (select user_id
from (select user_id as user_id, row_number() over() as rownumber
from user_rank
where ... additional parameters ...
order by rank desc) as maxrows
where rownumber <= :number)
and ... additional parameters ...
The table stores user ranking and I'm getting the top 5. The row_number() over() is just a trick for postgresql to be able to filter the top 5 in the outer query.
My closest attempt was for Criteria and it looks like this,
ProjectionList pl = Projections.projectionList()
.add(Projections.property("id.userId"))
.add(Projections.sqlProjection("row_number() over() as rownum", new String[] {"rownum"}, new Type[] { new IntegerType() }));
DetachedCriteria subCriteria = DetachedCriteria.forClass(UserRank.class)
.addOrder(Property.forName("rank").desc())
.add(Property.forName("... additional ..."))
.add(Property.forName("... additional ..."))
.setProjection(pl)
Criteria criteria2 = session.createCriteria(UserRank.class)
.add(Property.forName("id.userId").in(subCriteria))
.add(Property.forName("... additional ..."))
which would work except for the fact that it does not select the top 5 users. I cannot add the following to subCriteria
.add(Restrictions.sqlRestriction("rownum <= 5"));
because the column rownum does not exist yet. And there is no way to add it in the in statement of criteria2. I guess I could paginate over the results and it would not be too slow?
I could also solve it like this surely it would be slower.
Criteria usersC = session.createCriteria(UserRank.class)
.addOrder(Property.forName("rank").desc())
.add(Property.forName("... additional ..."))
.add(Property.forName("... additional ..."))
.setProjection(pl);
// Java code that fetches from the query and creates the list `users`
Criteria criteria = session.createCriteria(UserPageRankEvolution.class)
.add(Restrictions.in("id.userId", users))
.add(Property.forName("... additional ..."))
With HDL I didn't get even closed.
Many thanks for your patience and for your help.

Hibernate 2 with MSSQL for ORDER BY

I have been working with Oracle and Postgre and recently switched to MS SQL 2012.
I use hibernate in my application and wherever I have used the Order by Criteria:
(criteria.addOrder(Order.asc("applicationId")));
It causes an error saying:
aggregate functions dont work.
Once I comment that line out my program works and data can be retrieved.
I'm using Hibernate 3.
Is there any way to order it through hibernate without this error?
edit..
This is one error I get,
Column "SKY.tcrent.RENTNO" is invalid in the ORDER BY clause because
it is not contained in either an aggregate function or the GROUP BY
clause.
Edit 2..
MY query
Query tcSchaduleQ = getSession().createQuery("SELECT SUM(tcs.dueAmount) FROM TrialCalculationSchedule tcs WHERE tcs.facilityId=:facilityId AND tcs.rentalNumber>:rentalNumber AND tcs.dueDate>:dueDate AND dueTypeId IN(:dueTypeId) ORDER BY tcs.rentalNumber ").setInteger("rentalNumber", facility.getPeriod() - noOfprePayments).setInteger("facilityId",facility.getFacilityId()).setDate("dueDate", date).setParameterList("dueTypeId", plist);
Number tcsAmt = (Number) tcSchaduleQ.uniqueResult();
and this is what hibernate generates in HQL
SELECT
SUM(tcs.dueAmount)
FROM
TrialCalculationSchedule tcs
WHERE
tcs.facilityId=:facilityId
AND tcs.rentalNumber>:rentalNumber
AND tcs.dueDate>:dueDate
AND dueTypeId IN(
:dueTypeId
)
ORDER BY
tcs.rentalNumber
and this is the SQL
select
SUM(trialcalcu0_.DUEAMT) as col_0_0_
from
SKYBANKSLFHP.tcrent trialcalcu0_
where
trialcalcu0_.FACID=?
and trialcalcu0_.RENTNO>?
and trialcalcu0_.DUEDATE>?
and (
trialcalcu0_.DUETYPEID in (
? , ?
)
)
order by
trialcalcu0_.RENTNO
Look Like you mix aggregate and non-aggregate expressions .If you are using any aggregate function like AVG() in Select query with some other non-aggregate then you must use Group By ..
Try something like this
createQuery("SELECT SUM(tcs.dueAmount) As DueAmount ...
If you are using Criteria then it should be like this
Criteria crit = sess.createCriteria(Insurance.class);
ProjectionList proList = Projections.projectionList();
proList.add(Projections.sum("investementAmount"));
crit.setProjection(proList);
List sumResult = crit.list();

Need help creating JPA criteria query

I'm building my first Java EE web application using Glassfish and JSF. I'm fairly new to the criteria query and I have a query I need to perform but the javaee6 tutorial seems a little thin on examples. Anyway, I'm having a hard time creating the query.
Goal: I want to pull the company with the most documents stored.
Companies have a OneToMany relationship with Documents.
Documents has a ManyToOne relationship with several tables, the "usertype" column distinguishes them.
MySQL query:
SELECT USERID, COUNT(USERID) AS CNT
FROM DOCUMENTS
WHERE USERTYPE="COMPANY"
GROUP BY USERID
ORDER BY CNT DESC
Thanks
--update--
Based on user feedback, here is what I have so far:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Documents> cqry = cb.createQuery(Documents.class);
//Intersting Stuff
Root<Documents> root = cqry.from(Documents.class);
Expression userid = root.get("userID");
Expression usertype = root.get("userType");
Expression count = cb.count(userid);
cqry.multiselect(userid, count);
Predicate userType = cb.equal(usertype, "COMPANY");
cqry.where(userType);
cqry.groupBy(userid);
cqry.orderBy(cb.desc(count));
//more boilerplate
Query qry = em.createQuery(cqry);
List<Documents> results = qry.getResultList();
The error I get is:
Exception Description: Partial object queries are not allowed to maintain the cache or be edited. You must use dontMaintainCache().
Typical error, means nothing to me!
Your query doesn't return a complete entity object as you're only selecting two fields of the given table (this is why you're getting an error that says yadayadapartialyadayada).
Your solution is almost right, here's what you need to change to make it work—making it partial.
Instead of a plain CriteriaQuery<...> you have to create a tuple CriteriaQuery<..> by calling CriteriaBuilder.createTupleQuery(). (Basically, you can call CriteriaBuilder.createQuery(...) and pass Tuple.class to it as an argument. Tuple is a sort of wildcard entity class.)
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq= cb.createTupleQuery();
Root<Documents> root = cq.from(Documents.class);
Expression<Integer> userId = root.get("USERID");
Expression<String> userType = root.get("USERTYPE");
Expression<Long> count = cb.count(userId);
cq.multiselect(userId.alias("USERID"), count.alias("CNT"));
cq.where(cb.equal(userType, "COMPANY");
cq.groupBy(userId);
cq.orderBy(cb.desc(count));
TypedQuery<Tuple> tq = em.createQuery(cq);
for (Tuple t : tq.getResultsList()) {
System.out.println(t.get("USERID"));
System.out.println(t.get("CNT"));
}
(Accessing fields of a Tuple gave me an error if I didn't use aliases for them (in multiselect(...)). This is why I've used aliases, but this can be tackled more cleanly by using JPA 2's Metamodel API, which is described in the specification quite thoroughly. )
The documentation for CriteriaQuery.multiselect(...) describes the behaviour of queries using Tuple objects more deeply.
If you are using Hibernate, this should work:
ProjectionList pl = Projections.projectionList()
.add(Projections.groupProperty("userid"))
.add(Projections.property("userid"))
.add(Projections.count("userid"));
Criteria criteria = session.createCriteria(Document.class)
.add(Restrictions.eq("usertype",usertype))
.setProjection(pl)
.addOrder(Order.desc("cnt"));
Hope it helps!
Take a look into this easy tutorial. It uses JPA2 and Criteria
http://www.jumpingbean.co.za/blogs/jpa2-criteria-api
Regards!
You need to add a constructor to Documents with only userid and count because you will need it on:
cqry.multiselect(userid, count);

Categories