Hibernate group by with counts - java

In SQL I can do something like this:
select m.*,sq.c from message m inner join (
select max(m.id) as id, count(m.id) as c
from message m group by m.externalid
) sq on sq.id=m.id;
i.e. group the messages table, select by max(id) for each group and then return all the columns plus a count.
Can I do this in Hibernate (ideally JPQL) returning the Messages object plus the count value?
Or what's the best alternative - one query to fetch messages and then a separate one for the counts seems like it could go wrong. But I'm reluctant to have to trawl over a List if I can avoid it.
Edit:
This is as close as I can get to the equivalent Apple example from the link in the comments:
select new com.example.MessageStat(m, count(m)) from message as m group by m.externalid
But it gives this error:
ERROR [2018-08-22 11:35:54,600] org.hibernate.engine.jdbc.spi.SqlExceptionHelper: ERROR: column "message0_.id" must appear in the GROUP BY clause or be used in an aggregate function
Which I had with the SQL before adding the inner join, but I haven't been able to figure out the equivalent JPQL for that.

Related

SQL: How to make a query, that checks if rows with certain value on a column, refer to a foreign key more than once?

The database I'm working on has tables services and orders.
Each service has a foreign key reference as a column fk_order.
Now, services have a type column. Whenever a new order is created in the web-app, they'll automatically get a service the type of which is 'ORDERHANDLE'
There was a bug at some point that MIGHT have created a situation where some orders would've ended up with more than one service with the type 'ORDERHANDLE' referring to them.
What I'd like to do now is to make a query, that checks if there are multiple (more than one) service rows with the type 'ORDERHANDLE' referring to one fk_order. Because only one ORDERHANDLE type of service should be referring to one order.
Thank you for any advice.
Here is my query so far (yes I'm a noob.)
SELECT * FROM services
INNER JOIN orders
ON services.fk_order = order.id
WHERE services.type = 'ORDERHANDLE'
I just have no idea how to proceed from there.
You need to perform an aggregation of the services table. You will need to use the COUNT function to count the number of ORDERHANDLE occurences. I'm not proficient with sql-server but something like this should work:
SELECT count(services.id) FROM orders
INNER JOIN services
ON services.fk_order = order.id
WHERE services.type = 'ORDERHANDLE'
GROUP BY orders.id
HAVING count(services.id) > 1
You can identify rows with more than 1 foreign key reference like this:
SELECT orders.id, count(*) cnt
FROM services
INNER JOIN orders
ON services.fk_order = order.id
WHERE services.type = 'ORDERHANDLE'
GROUP BY orders.id
HAVING count(*) > 1

Preserve order with Select...Where In and lock the lines

I have the following prepared statement in java:
with main_select as
(select request_id,rownum iden
from
(select request_id
from queue_requests
where request_status = 0 and
date_requested <= sysdate and
mod(request_id,?) = ?
order by request_priority desc, oper_id, date_requested)
where rownum < ?)
select *
from queue_requests qr, main_select ms
where qr.request_id in ms.request_id
order by ms.iden for update skip locked;
It doesn't execute:
ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.
I'll try to explain why i need all the select statements:
the first (inner) select obtains the data i need
the second one limits the number of lines to a number (i can't put it in the first select, because oracle firstly limits the results and only after orders them, which is not what i want)
the third (outside with) select preserves the order (i tried using 3 nested selects - so, no with clause - but i can't find a way to preserve the order in this case). Also, it should lock the lines in the queue_requests table, but because i selected data from the with clause, it gives the above error.
So, i want to select data from queue_requests, keep the first x lines, preserve the order of the select and lock the lines.
Is there a way to do it?
The problem seems to be, that you want to set a lock on the result of main_select. I would just guess, that you can do select for update in the select in the with clause like:
with main_select as
(select request_id,rownum iden
from (subselect)
where rownum < ?
for update skip locked)
But as I said lucky guess.

Determine if JOIN resulted in any columns

I have a sql statement with multiple joins; sometimes there are records resulting from the joins and sometimes not. It is not an error when the joins are empty.
Is there a way to test whether a particular join is empty without having to trap the exception occurring when a resulting column is not found in the result set?
In other words, if, using JDBC, I execute the following sql statement:
select * from AA left outer join BB on AA.keyField = BB.keyField
where keyField = "123"
I would like to know whether that join found any fields without having to trap an exception. If I then execute the java statement:
String valueString = rs.getString("BB.keyField");
I get an exception. I cannot compare rs.getString("BB.keyField") to null, because the getString throws an exception if it did not find any values in the join.
I hope this makes the question more clear, and I apologize for not having expanded on it more in the first place.
The query won't return columns with such names. It will just use the simple names of the columns (name, keyField, etc.). Execute the query inside your database query tool, and you'll see which names are assigned to the retrieved columns.
You should never do a select *, and always select specific columns. And you should assign aliases to columns if two columns have the same name:
select AA.id as aId, AA.name as aName, BB.id as bId, BB.name as bName from ...
And, then, you can safely use
rs.getString("aId");
rs.getString("bName");
...
Also, the exception thrown contains a message, which should help you identify the problem. Read it. And if you don't understand it, post it.

How to order by count() in JPA

I am using This JPA-Query:
SELECT DISTINCT e.label FROM Entity e
GROUP BY e.label
ORDER BY COUNT(e.label) DESC
I get no errors and the results are sorted almost correct but there are some values wrong (either two values are flipped or some single values are completly misplaced)
EDIT:
Adding COUNT(e.label) to my SELECT clause resolves this problem for this query.
But in a similar query which also contains a WHERE clause the problem persists:
SELECT DISTINCT e.label, COUNT(e.label) FROM Entity e
WHERE TYPE(e.cat) = :category
GROUP BY e.label
ORDER BY COUNT(e.label) DESC
You might need to include the COUNT(e.label) in your SELECT clause:
SELECT DISTINCT e.label, COUNT(e.label)
FROM Entity e
GROUP BY e.label
ORDER BY COUNT(e.label) DESC
UPDATE: Regarding the second query please read section 8.6. Polymorphic queries of the EntityManager documentation. It seems that if you make your queries in a way that requires multiple SELECTs, then the ORDER BY won't work anymore. Using the TYPE keyword seems to be such a case. A quote from the above link:
The following query would return all persistent objects:
from java.lang.Object o // HQL only
The interface Named might be implemented by various persistent classes:
from Named n, Named m where n.name = m.name // HQL only
Note that these last two queries will require more than one SQL SELECT. This means that the order by clause does not correctly order the whole result set. (It also means you can't call these queries using Query.scroll().)
For whatever reason the following style named query didn't work for me:
SELECT DISTINCT e.label, COUNT(e.label)
FROM Entity e
GROUP BY e.label
ORDER BY COUNT(e.label) DESC
It could be because I am using an old version of Hibernate. I got the order by working by using a number to choose the column to sort by like this:
SELECT DISTINCT e.label, COUNT(e.label)
FROM Entity e
GROUP BY e.label
ORDER BY 2 DESC
Can't see how the order could be incorrect. What is the incorrect result?
What is the SQL that is generated, if you try the same SQL directly on the database, does it give the same incorrect order?
What database are you using?
You could always sort in Java instead using sort().

Query problems with Hibernate (JPA) and PostgreSQL

I'm trying to use PostgreSQL as the database for Hibernate/JPA. However, I get an error when executing a simple query. My query is as follows:
SELECT DISTINCT p FROM UserProfile p ORDER BY :order
When I execute the query, I'll pass in a value like "lastLoginDate" for :order. However, I get the following exception when trying to execute the query:
ERROR org.hibernate.util.JDBCExceptionReporter - ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
Position: 781
This query works just fine using MySQL as the database, but we'd like to move towards PostgreSQL. My overall configuration and database connection is correct, as I see the tables being created properly. Is there something I'm missing? Is there a configuration property I need to set? Any help you can give would be MUCH appreciated. Thanks!
Postgresql prohibits that query because it is ambiguous:
there's actually a definitional reason for it. Consider
SELECT DISTINCT x FROM tab ORDER BY y;
For any particular x-value in the table there might be many different y
values. Which one will you use to sort that x-value in the output?
It's not very clear what you want (an example?), but if you intend to sort all records by ':order' column, and then remove duplicated values, you can do that first with DISTINCT ON: , and then reorder:
SELECT p FROM
( SELECT DISTINCT ON (p) * from UserProfile ORDER BY p , :order)
AS UserProfileUniq
ORDER BY :order ;

Categories