Getting the occurrence of values using JpaRepository Queries - java

I have a class named Submission and another SubmissionDAO for the repository. The submission class has a number of fields such as id, author, title,...
What I want to do is search through the database and get a list of (count, author) pairs for each author value in the database.
I made a query
#Query(value = "select author, count(*) from submissions GROUP BY author order by count(author) desc", nativeQuery = true)
List<Submission> findByAuthorOccurance();
Obviously, this doesn't work because it can't put the count value in the Submission object.
My question is how would I go about getting this pair of values back to my controller?
I've tried searching but nothing comes up.

In case anyone comes here in the future for whatever reason, I figured my problem out.
When you specify a range of data points to get from the query (ie author and count), it groups the values into object arrays (Object[]) and puts those in a normal List.
So my code ended up being like this:
#Query(value = "select author, count(*) from submissions GROUP BY author order by count(author) desc", nativeQuery = true)
List<Object[]> findByAuthorOccurance();
For the query and
List<Object[]> map =submissionRepository.findByAuthorOccurance();
for(Object[] objs : map){
System.out.println((String)objs[0]+" : "+(BigInteger)objs[1]);
}
To get the data.

Related

How to get data from raw query in spring boot?

I have a query:
Query q = em.createNativeQuery("select DISTINCT id, rating, random() as ordering FROM table\n" +
" WHERE id not in (1,2) ORDER BY ordering LIMIT 10");
List data = q.getResultList();
Every element of this list is array like object:
I want to retrieve that "8" and "16" and compose a comma separated string (to use it in my query in "not in" section in future):
for (Object x : data) {
System.out.println(Arrays.asList(x).get(0));
}
But it produces strings:
[Ljava.lang.Object;#ee93cd3
[Ljava.lang.Object;#62f3c3e1
I don't know how to get that IDs ("8" and "16")
1.I think this is what you are looking for...
Convert JPA query.getResultList() to MY Objects.
or
List<Object[]> rows = q.getResultList(); for (Object[] row : rows) { System.out.println(row[0]); }
in this line
List<Object[]> data = q.getResultList();
data is list of Object of form
[ [1,233, 0.000333], [1,233, 0.000333] ]
for (Object[] x : data) {
// x is [1,233, 0.000333]
System.out.println(x[0]);
}
If I understood it correctly, you are looking for comma separated string of ID's.
If so, then follow these steps might help you to solve the issue.
Create a constructor in table which has only one parameter ID. (If you want you can add more parameters as well but make sure the value which you want it must be in constructor as well as in query.)
Write sql query and execute it.
It returns result and gather it in List which contains the object of the table.
Get the string
dataList.stream().map(obj -> obj.getId()).collect(Collectors.joining(", "))
This will give you the comma separated string.

Nested SQL in #Query tag is not working properly

Suppose I have a table which contains all the accounts of user and type.
I want to make a Jpa Repository method which returns an array of total number of each type of user (USER, ADMIN, MASTER).
Here is how I did it in JpaRepository:
#Query(value="SELECT (SELECT COUNT(*) FROM account WHERE account_role='USER'),"
+ "(SELECT COUNT(*) FROM account WHERE account_role='ADMIN'),"
+ "(SELECT COUNT(*) FROM account WHERE account_role='MASTER')"
+ "FROM account LIMIT 1",
nativeQuery=true)
public List<Integer> getTotalAccountType();
The code executed fine, but the result wasn't what I expected.
Result:
[2]
Expected result: [2,10,30]
Any idea how would I use nested SQL with JPQL? Thank you in advance!
If repository method returns List of Integers it means that query result row contains an Integer value. But you expect to get sequence of Integers in one row.
You can get same result different way:
#Query(value="SELECT COUNT(*) FROM account WHERE account_role=?", nativeQuery=true)
public Integer getTotalAccountType(String role);
and then:
Integer userCount = repository.getTotalAccountType("USER");
Integer adminCount = repository.getTotalAccountType("ADMIN");
Integer masterCount = repository.getTotalAccountType("MASTER");
or if you have mapped entity:
create Pair<K,V> class with constructor Pair(K key, V value) or use it from any external library
repository method based on hql query
#Query(value="select new javafx.util.Pair(a.accountRole, count(a)) from Account a group by a.accountRole")
public List<Pair<String, Integer>> getRoleCountList();
convert repository result to a Map<String, Integer> in service
javafx.util.Pair<String, Integer> result = repository.getRoleCountList();
Map<String, Integer> map = result.stream().collect(Collectors.toMap(r-> r.getKey(), r-> r.getValue()));
Try returning Object[] rather than a List<Integer>. I think returning List<Integer> would indicate multiple rows of an Integer value are being returned, whereas you're getting back one row with multiple Intger columns.
From the resulting Object[] you would pull out the first value (indicating a row). This should be another Object[], which will have your values in the order returned.
You can also remove that last "FROM account LIMIT 1" line, as it has no bearing on the result.
I would recommend casting all of this to an object though. As seen here -
How to return a custom object from a Spring Data JPA GROUP BY query

Pagination with ordered data with hibernate

Using hql in hibernate we can do pagination on a table data using below, but below will return first 5 data records in the table.
String SQL_QUERY = "FROM Order order";
Query query = session.createQuery(SQL_QUERY);
query.setFirstResult(1);
query.setMaxResults(5);
But how can i do the pagination on a ordered data on a table for example an ordered data set by a order_id ?
Not sure what you're asking, but just add order by clause in your query, and calculate first result based on page. Something like this
String HQL_QUERY = "FROM Order o order by o.id";
Query query = session.createQuery(HQL_QUERY);
// page size
query.setMaxResults(5);
// page 1
query.setFirstResult(1);
// page 2
query.setFirstResult(6);
...

Hibernate result list cast to get rows

Hello I had problem with iterate Hibernate ResultList
I had followed query that I got from external class:
queryContent = "select distinct c.identity, c.number, c.status, ctr.name, aab.paymentConditions.currency from AgreementStateBean ast join ast.currentAgreement aab join conagr.contract c where c.agreementStateId = ? and con.mainContractor = true ? "
And I must sum whole aab.paymentConditions.currency, check numbers of statutes and names.
I want to do this by iterate list of results:
Query q = session.createQuery(queryContent);
List result = q.list();
Long wholeCurrency, numberOfStatutes;
for(Object res : result){
//wholeCurrency += res.getColumnName?
}
My question is how to cast res Object to have possibility to get concrete column values? I had read about create map inside hibernate query but I don't know it is good practice to modyfied query string by adding
"new map(" prefix and then ")"
before from sql statement
Solution:
After All I decided to use map in my query. I modified my external query by adding hibernate map statement by replacing select by 'select new map(' and from by ') from'.
Additional thing is to add 'as' statement with name of key because without them column keys are integer.
So after all my query looks like follow:
"select new map( distinct c.identity, c.number, c.status as status, ctr.name as name, aab.paymentConditions.currency as currency ) from AgreementStateBean ast join ast.currentAgreement aab join conagr.contract c where c.agreementStateId = ? and con.mainContractor = true ? "
That was the most siutable solution for me, I tried with 'NEW com.example.MyClass' as Kostja suggested but in my case I didn't have control for incoming query so I can not rely on pernament constructor.
new List( select...
Is also interest but it also didn't tell me on with position I have my field that give me information.
If I understand correctly, you want to have a typed representation of your result without it being an entity itself. For this, you can use constructor queries:
"SELECT NEW com.example.MyClass( e.name, e.data) FROM Entity e"
MyClass has to have a matching constructor. Full qualification (com.example) is not mandatory AFAIK.
If you are using this query often, creating a view in the DB may be a good idea. You can map a view to an entity just as if it were a regular table, but please note that you cannot store changes to you data over a mapped view.
EDIT: Turns out, mapping to an unspecified Map is alright with Hibernate:
select new map( mother as mother, offspr as offspr, mate as mate )
As per http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch11.html#ql-select-clause
you can use
queryContent = "select new list(distinct c.identity, c.number, c.status, ctr.name, aab.paymentConditions.currency) from AgreementStateBean ast join ast.currentAgreement aab join conagr.contract c where c.agreementStateId = ? and con.mainContractor = true ? "
And you get List<List> as result.

How to send send an array of objects to a NamedQuery that needs the "id" of all the objects.

I am building a report from information received from a muti-select form element in a jsp page.
In my repository class I am getting an array of objects from that element. I need to call the getId function for each one of these objects and send those ids to the NamedQuery.
Here is a code example to help explain. I know how to handle a single object but with an array of objects I get lost at the .setParameter(1, employees[].getId()) part.
public List<RequestByRequester> getFormInformation(
Employee[] employees)
throws NoDataFoundException {
List<RequestByRequester> resultList = getEm().createNamedQuery(
"requestByRequestor.getRequestsByRequesters", RequestByRequester.class)
.setParameter(1, employees[].getId())
.getResultList();
return resultList;
}
By request the query:
SELECT EMP.EMPL_FIRST_NAME || ' ' || EMP.EMPL_LAST_NAME REQUESTER,
R.RQST_ID RQST_ID,
R.TITLE TITLE,
R.DESCRIPTION DESCR,
DECODE(R.RESOLUTION_DATE, NULL, 'Open', 'Closed') STAT
FROM TARTS.REQUESTS R, SYS_EMPLOYEES EMP
WHERE R.EMPL_ID_REQUESTED_BY = EMP.EMPL_ID
AND EMP.EMPL_ID IN (?)
ORDER BY 1, 5 DESC, 2
I tried calling Madame Mystique to get help with finding out what your query actually was, but no luck, so I'm just going to go for it...
Your named query should look something like this:
select x
from MyClass x
where x.children.id in (:ids)
then get your ids into a list
List<Integer> ids = new ArrayList<Integer>();
ids.add(someid); // etc
then use this to specify it in your query
.setParameter("ids", ids)

Categories

Resources