How can I divide two HQL Count Results? - spring

I want to compute the percentage of people who are not active divided by the percentage of people being active.
I will do something like the following HQL query but it did not work:
(select count(x) from People as x where x.active=false) /
(select count(x) from People as x where x.active=true)
How can I do that?

You can use a group by clause to express this. Here's how you could do it in Grails:
def countByAction = People.
executeQuery("select active, count(*) from People group by active")*.
toList().
collectEntries{it}
println (countByAction[true])
println (countByAction[false])

Since you are using HQL expression, I'm assuming you are using Hibernate. In this case I would recommend you using #Formula annotation. You may find additional information here:
Hibernate documentation - search for #Formula
Example of using #Formula annotation

Something like this should work
String hql = "select count(x)/(select count(x) from People as x where x.active=true)
from People as x where x.active=false";
Long result = (Long) em.createQuery(hql).getSingleResult();
NOTE: above is untested

I use countBy* Dynamic method that uses the properties of the domain class to query for the count of the number of matching records. see http://grails.org/doc/latest/ref/Domain%20Classes/countBy.html

Related

JPA #Query count AND select

I have a somewhat complicated #Query in a JpaRepository.
I need to get the results of this query in two forms (but not at the same time!):
First, the client asks for a count of the number of results: SELECT COUNT(x.*) FROM my_table x ...
Then later (maybe), they want to see the actual data: SELECT x.* FROM my_table x ...
What follows (the ...) is identical for both queries. Is there any way to combine these so that I don't repeat myself?
I know I could just use the second method, and count the number of elements in the resulting List. However, this adds the overhead of actually fetching all those elements from the database.
I could put the ... in a String constant somewhere, but that kind of separates it from its context (I'd lose IntelliJ's syntax highlighting/error checking)
I can't convert it to a Criteria or Example query, because I need to use PostGIS's geography type. (And these are less readable anyway...)
Any other ideas?
If your worries is about some developer change the COUNT query and forgot to change the SELECT query too, you can create a repository integration test to guarantee the expected result between the two queries.
Another alternative is create a unit test to read the annotation content and verify if the final of these two queries are equal.

Pagination with JPA and Oracle database

This week i was looking into a sorting issue in a WebApp. Sorting a table in the browser by a selected column did not work properly. It turned out that in the application, we used JPAs CriteriaQuery to create the query and then create a TypedQuery for the pagination as follows:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SomeEntity> q = cb.createQuery(SomeEntity.class);
Root<SomeEntity> c = q.from(SomeEntity.class);
q.select(c);
...
q.orderBy(cb.asc(c.get("SomeColumn")));
TypedQuery<> query = em.createQuery(q);
query.setFirstResult(pageIx * pageSize);
query.setMaxResults(pageSize);
...
This is pretty much how the documentation suggests to create queries (see here).
In the logs i saw that this generates an SQL query like this:
select * from (
select lots_of_columns from some_view order by selected_column
) where rownum <= 50
Since Oralce 10 the ordering of the enclosed select has no effect according to the documentation and, if i remember correctly, this also makes sense according to relational algebra. We use Oracle 12c.
So my question is, how am i supposed to takle this correctly?
I have found that offset and fetch should be used but i couldn't find how to tell JPA to generate the SQL accordingly. Also i have found a post that suggested to add the id to the order by clause, however this did not solve the problem either.
Thank you in advance for any thoughts and hints on the topic.

Oracle query with multiple tables

I am trying to display volunteer information with duty and what performance is allocated.
I want to display this information. However, when I run the query, it did not gather the different date from same performance. And also availability_date is mixed up. Is it right query for it? I am not sure it is right query.
Could you give me some feedback for me?
Thanks.
Query is here.
SELECT Production.name, performance.performance_date, volunteer_duty.availability_date, customer.name "Customer volunteer", volunteer.volunteerid, membership.name "Member volunteer", membership.membershipid
FROM Customer, Membership, Volunteer, volunteer_duty, duty, performance_duty, performance, production
WHERE
Customer.customerId (+) = Membership.customerId AND
Membership.membershipId = Volunteer.membershipId AND
volunteer.volunteerid = volunteer_duty.volunteerid AND
duty.dutyid = volunteer_duty.dutyid AND
volunteer_duty.dutyId = performance_duty.dutyId AND
volunteer_duty.volunteerId = performance_duty.volunteerId AND
performance_duty.performanceId = performance.performanceId AND
Performance.productionId = production.productionId
--Added image--
Result:
The query seems reasonable, in terms of it having what appear to be the appropriate join conditions between all the tables. It's not clear to me what issue you are having with the results; it might help if you explained in more detail and/or showed a relevant subset of the data.
However, since you say there is some issue related to availability_date, my first thought is that you want to have some condition on that column, to ensure that a volunteer is available for a given duty on the date of a given performance. This might mean simply adding volunteer_duty.availability_date = performance.performance_date to the query conditions.
My more general recommendation is to start writing the query from scratch, adding one table at a time, and using ANSI join syntax. This will make it clearer which conditions are related to which joins, and if you add one table at a time hopefully you will see the point at which the results are going wrong.
For instance, I'd probably start with this:
SELECT production.name, performance.performance_date
FROM production
JOIN performance ON production.productionid = performance.productionid
If that gives results that make sense, then I would go on to add a join to performance_duty and run that query. Et cetera.
I suggest that you explicitly write JOINS, instead of using the WHERE-Syntax.
Using INNER JOINs the query you are describing, could look like:
SELECT *
FROM volunteer v
INNER JOIN volunteer_duty vd ON(v.volunteerId = vd.colunteerId)
INNER JOIN performance_duty pd ON(vd.dutyId = pd.dutyId AND vd.volunteerId = pd.colunteerId)
INNER JOIN performance p ON (pd.performanceId = p.performanceId)

Hibernate Dynamic Order

Hi i want to sort in HQL
ORDER BY IF g.groupAdminId=:adminid THEN 1 ELSE 0 END ASC
But it doesn't work, i want to have all entities where the user is admin first, how can i archieve this?
I don't believe it is possible to put named parameters outside a where clause.
It is possible to order according to expressions:
from User U
order by case
when U.group.name = 'Admin' then 0
when U.group.name = 'Superuser' then 1
else 2
end asc
More on case in HQL docs :
For your particular problem (having admins before other users) I suggest making two queries and combining the two lists in Java.
There are other ways around this but I do not like any of them:
Multiple mappings
Custom functions

LINQ group by question

I started playing around with Linq today and ran into a problem I couldn't find an answer to. I was querying a simple SQL Server database that had some employee records. One of the fields is the full name (cn). I thought it would be interesting to group by the first name by splitting the full name at the first space. I tried
group by person.cn.Split(separators)[0]
but ran into a lengthy runtime exception (looked a lot like a C++ template instantiation error).
Then I tried grouping by a few letters of the first name:
group by person.cn.Substring(0,5)
and that worked fine but is not what I want.
I'm wondering about two things:
Why does the first example not work when it looks so close to the second?
Knowing that behind the scenes it's SQL stuff going on, what's a good way to do this kind of thing efficiently
Thanks,
Andrew
Split has no translation into SQL.
So, how to do this string manipulation without split? Cheat like hell (untested):
string oneSpace = " ";
string fiftySpace = " ";
var query =
from person in db.Persons
let lastname = person.cn.Replace(oneSpace, fiftySpace).SubString(0, 50).Trim()
group person by lastname into g
select new { Key = g.Key, Count = g.Count };
The reason your first attempt didn't work is because LINQ to SQL uses Expression Trees to translate your query into SQL. As a result any code that isn't directly translatable into SQL is an exception - this includes the call to Split.
Thanks guys, I'll try the "Replace" trick to see if that runs. I'm very intrigued by LINQ but now it looks like there's some hidden mysteriousness where you have to know what your LINQ queries translate into before being able to use it effectively.
The core problem is of course that I don't know SQL very well so that's where I'll start.
Edit:
I finally tried the "Replace" today and it works. I even got to sort the grouped results by count so now I have a pareto of name in my company. It's horrendously slow, though. Much faster to select everything and do the bucketing in C# directly.
Thanks again,
Andrew

Resources