CASE statement in HQL or Criteria - java

derived from this question, is it possible to use HQL or Criteria for the following SQL statement:
SELECT
e.type,
count(e),
count(d),
count (case when gender = 'male' then 1 else NULL end) AS NumberOfMaleEmployees
from Department d
JOIN d.employees e
WHERE e.dead = 'maybe'
GROUP BY e.type
Although google comes up with a few hits that state HQL supports CASE statements, Hibernate 3.6.6 fails with a
QuerySyntaxException: unexpected token: CASE
when I create the query above on an EntityManager instance.
How much of a bad idea is it, to create another query for every e.type to determine the number of males manually, e.g. for every e.type
SELECT
count(e),
from Department d
JOIN d.employees e
WHERE e.dead = 'maybe', e.type = ugly
Since there could be quite a few types, this is potentially slow. I'd like the database to do the work for me.

Well, it seems, case statements are supported:
http://docs.jboss.org/hibernate/core/3.5/reference/en/html/queryhql.html
They just don't seem to work within count(). An alternative would be using sum(case when... then 1 else 0 end) instead

Related

join and where clause in hibernate

I am using join and where clause in hibernate 3.but i cant reach the solution.I got the error.
Query qry= session.createQuery("SELECT addemployee.eid,addemployee.fname,addemployee.location,"
+ "empdet.jtitle,empdet.leadname FROM addemployee LEFT JOIN empdet ON addemployee.eid = empdet.eid WHERE (addemployee.eid ='"+id+"')");
List l = qry.list();
Iterator it=l.iterator();
while(it.hasNext())
{
Object rows[] = (Object[])it.next();
System.out.println(rows[0]+separator+rows[1]+separator+rows[2]+separator+rows[3]+separator+rows[4]);
}
Issue: org.hibernate.hql.ast.QuerySyntaxException: unexpected token: ON near line 1, column 127 [SELECT addemployee.eid,addemployee.fname,addemployee.location,empdet.jtitle,empdet.leadname FROM addemployee LEFT JOIN empdet ON addemployee.eid = empdet.eid WHERE (addemployee.eid ='206')]
Try to use session.createSQLQuery() instead.
and don't put enclosed apostrophe (''), you are inputting numbers, not varchar.
like this.
Query qry= session.createSQLQuery("SELECT addemployee.eid,addemployee.fname,addemployee.location,"
+ "empdet.jtitle,empdet.leadname FROM addemployee LEFT JOIN empdet ON addemployee.eid = empdet.eid WHERE (addemployee.eid ="+id+")");
Hibernate Session's createQuery() method requires valid HQL syntax. You can check how to write joins here.
Basically, in HQL you work with your entities, not SQL tables. So you don't need to write ON, because you already map association between entities.
If you still want to write native SQL query, you need to use
session.createSQLQuery(); instead

criteria api multiselect with count and distinct not working

SELECT a.id,COUNT(entity2.number)
AS "numbers" ,SUM(CASE WHEN entity2.status= 'A' THEN 1 ELSE 0 END)
AS "blocked" FROM entity1 a
LEFT OUTER JOIN entity ON a.id = entity2.id
WHERE a.id LIKE 'ZX13%'
GROUP BY a.id.
i am using criteria builder api to perform above operation.
If i use criteriaQuery.multiselect(listSelections).groupBy(a.id) it works fine but when i use criteriaQuery.multiselect(listSelections).distinct(true).groupBy(a.id) it is not working fine. I want distinct results too.
Why it is not working as expected?
How to resolve this?

jpa native query not returning all values

I am using jpa native query , but its not returning values from salias it returns values from S
Query query = em.createNativeQuery("Select S.\"MESSAGE\",S.\"DESTINATION\",S.\"SENT_DATE\",S.\"CLIENT_TRACKING_ID\",S.\"MESSAGE_COST\",S.\"sTId\",salias.\"STATUS\",salias.timeDate from \"sent_sms_view\" S left join ( Select Distinct on (\"SMS_ID\") R.\"SMS_ID\",R.\"STATUS\",R.timeDate from \"sms_receipt_view\" R Order By R.\"SMS_ID\",R.timeDate Desc)As salias on S.\"SYSTEM_TRACKING_ID\"=salias.\"SMS_ID\" where S.Id_systemUser=:systemUser and S.\"CLIENT_TRACKING_ID\"=:cTId");
query.setParameter("cTId", cTId);
query.setParameter("systemUser", systemUser);
if (query.getResultList().size() > 0){
List<Object> resultat = query.getResultList();
This is the Postgres query and it works fine
Select S."MESSAGE",S."DESTINATION",S."SENT_DATE",S."CLIENT_TRACKING_ID",S."MESSAGE_COST",S."sTId" ,salias."STATUS",salias.timeDate
from "sent_sms_view" S
left join ( Select Distinct on ("SMS_ID") R."SMS_ID",R."STATUS",R.timeDate from "sms_receipt_view" R Order By R."SMS_ID",R.timeDate Desc)As salias
on S."SYSTEM_TRACKING_ID"=salias."SMS_ID"
where S.Id_systemUser='101' and S."CLIENT_TRACKING_ID" ='abda';
Can anyone tell me what i am doing wrong.
I'm only guessing what you might be trying to do, since you haven't told us, but here's how I'm guessing it should probably look like:
SELECT S."MESSAGE", S."DESTINATION", S."SENT_DATE", S."CLIENT_TRACKING_ID", S."MESSAGE_COST", S."sTId", salias."STATUS", salias.timeDate
FROM "sent_sms_view" S
INNER JOIN "sms_receipt_view" AS salias on (S."SYSTEM_TRACKING_ID" = salias."SMS_ID")
WHERE S.Id_systemUser=:systemUser AND S."CLIENT_TRACKING_ID"=:cTId
However I don't see why you would have numerical IDs, such as Id_systemUser stored as strings. In fact that variable name indicates horrible database design. CamelCasing combined with underscores is something you must categorically avoid.
And you must never call query.getResultList() twice if you're looking for the same results. Simply store the List to a local variable and then use it.

HQL - COUNT on SELECT clause not working

I'm trying to create an HQL query that calculates several stats on a list on specific users for specific dates (for example, how many were logged in etc.). Each stat has a different criteria):
SELECT
COUNT(SELECT u2.id FROM User u2 WHERE u.id = u2.id AND u2.lastLoginDate BETWEEN x AND y),
COUNT(some other stats), ...
FROM User u
WHERE u.managerId IN (...)
While the COUNT(SELECT...) clause worked in MySQL, in HQL I get the following exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: SELECT
Anyone know how to make it work?
EDIT:
Ok, So according to this suggestion HQL - COUNT on SELECT clause not working now the query looks something like this:
SELECT
COUNT(DISTINCT CASE WHEN u.lastLogin BETWEEN x AND y THEN u.id ELSE null END),
COUNT(DISTINCT CASE WHEN ... END),
SUM(CASE WHEN u.id = p.userId THEN p.amount ELSE null END),
FROM User u, Points p,... WHERE u.managerId IN (...)
Problem is, the calculated SUM is not correct because of the From clause - it's multiplied by the number of tables.
For example if the total sum should be 80, and I have 4 tables in the from clause, the sum is instead 480!
Obliviously, distinct won't work correctly for sum. Any ideas?
It seems that you just want conditional aggregation. It is unclear what you really want from the query, but this may be close:
SELECT COUNT(*) as cnt1,
SUM(CASE WHEN u2.lastLoginDate BETWEEN x AND y THEN 1 ELSE 0 END) as cnt2,
SUM(CASE WHEN some other stats THEN 1 ELSE 0 END), ...
FROM User u
WHERE u.managerId IN (...)
I am surprised that count(select . . . ) worked in MySQL. First, subqueries usually require their own parentheses. Second, in a select, a subquery generally needs to be a scalar subquery. And third, subqueries are generally not allowed as arguments to aggregation functions. Are you sure the construct wasn't select count() . . .?
You can use native SQL.
Here is an example.
String sql = "select {user.*} from User user";
// here creates a hql query from sql
SQLQuery query = session.createSQLQuery(sql);
query.addEntity("user", User.class);
List results = query.list();
//Hibernate modifies the SQL and executes the following command against the database:
select User.id as id0_, User.name as name2_0_ from User user
you can search for Native SQL.
Hope this will help.

In jpa criteria, "in case there is at least 1 row return true"

I'm trying to create the follow sentence using the criteria api in JPA (eclipselink),
it simple ask if there exist some user in some category
The sentence I want:
SELECT
CASE
WHEN EXISTS
(SELECT * FROM user WHERE category = ?)
THEN true
ELSE false
END
bind => [10]
I trying using this code:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Boolean> criteriaQuery = criteriaBuilder.createQuery(Boolean.class);
Root<T> root = criteriaQuery.from(tclass);
Subquery<T> subquery = criteriaQuery.subquery(tclass);
Root<T> subroot = subquery.from(tclass);
subquery.select(subroot);
Predicate subPredicate = criteriaBuilder.equal(subroot.get("category"),category);
subquery.where(subPredicate);
Predicate predicateExists = criteriaBuilder.exists(subquery);
Case<Boolean> booleancase = criteriaBuilder.<Boolean>selectCase();
Expression<Boolean> booleanExpression =
booleancase.when(predicateExists,true)
.otherwise(false);
criteriaQuery.select(booleanExpression);
TypedQuery<Boolean> typedQuery = entityManager.createQuery(criteriaQuery);
typedQuery.getResultList();
Sadly the sentence I have is the follow, I want to erase the last "from user":
SELECT
CASE
WHEN EXISTS
(SELECT ? FROM user t1 WHERE (t1.category = ?))
THEN ?
ELSE ?
END
FROM user t0
bind => [1, 110, true, false]
Any idea?
Unfortunately, JPA does not support selecting data without an entity (table). Not even standard SQL92 supports this - have a look at how you can select without a table in different databases: http://en.wikibooks.org/wiki/SQL_Dialects_Reference/Select_queries/Select_without_tables
In SQL92 standard, you must provide table in SELECT clause.
JPA is also a widely accepted standard and usually does not provide non-standard features and even many standard SQL features come only in latest versions of JPA (for example nested selects came only recently with JPA 2.1 in JavaEE 7).
So the solution is to select from some entity, which always has at least one row in database, and limit the results to max 1 by query.setMaxResults(1). Even better is to create a dummy entity, which always has 1 row and its contents is never changed. This would increase performance of the select.
Finally I work around :P
TypedQuery<Boolean> typedQuery =
entityManager.createQuery(criteriaQuery).setMaxResults(1);
Then the sentence (is not the same, but is very close):
SELECT
CASE
WHEN EXISTS
(SELECT ? FROM user t1 WHERE (t1.category = ?))
THEN ?
ELSE ?
END
FROM user t0 LIMIT ?, ?
bind => [1, 110, true, false,0,1]

Categories

Resources