Sum column values in JPQL - java

I am workin on an evaluation system, and I need to retrieve the sum of the values of each answer given by the person that is evaluating.
This is the query I have now:
SELECT e.evaluado.nombre, e.evaluado.apellido, e.evaluador.nombre, e.evaluador.apellido,
(pd.puntaje*rc.escala.valor/SIZE(c.preguntaCerradaCollection)), e.evaluado.centroCosto.descripcion
FROM Criterio c, PreguntaCerrada p, Redacciones r,
Evaluacion e, RespuestaPreguntaCerrada rc, Ponderacion pd, Escalas es
WHERE c.preguntaCerradaCollection = p
AND r.preguntaCerrada = p
AND r.instrumentos = e.idInstrumento
AND e.respuestaPreguntaCerradaCollection = rc
AND rc.preguntaCerrada = p
AND pd.criterio = c AND pd.instrumentos = e.idInstrumento
AND rc.escala = es
AND e.idPeriodo.idPeriodo = '2013-p1'
ORDER BY e.evaluado.nombre, e.evaluador.nombre, c.descripcion, e.evaluado.centroCosto
So, I have here, the Criteria, Questions, Answers, values of each Criteria, etc. This column is the one that gives back the numeric values of each answer:
(pd.puntaje*rc.escala.valor/SIZE(c.preguntaCerradaCollection))
But I need the total of those values for each employee because I need to know who were the 'n' best employees, or the worst.
If I use the SUM function, the query executor returns this:
Error 130: Cannot perform an aggregate function on an expression containing an aggregate or a subquery
What could be the solution for this?
Thanks in advance

Related

Generate Dynamic Query using JOOQ

I want to generate a SQL query where tables name is stored in the tables array.
and the corresponding columns name stored in a 2-D array.
example:-
Tables array
[T1,T2,T3]
Columns array
[
[C1,C2], // T1 columns
[C1,C2], // T2 columns
[C1,C2] // T3 columns
]
QUERY:-
select T1.C1,T2.C1,T3.C1 from T1
inner join T2 ON T2.C2=T1.C2;
inner join T3 ON T3.C2=T1.C2
select first column of every table in the array
if they have a match in the second column
[assuming every table has 2 columns]
I don't want to execute this query.
I just want to print it using JOOQ.
Can someone pls help me out on this.
The phrasing of your question gives room to some interpretation. I'm assuming you have these specific array types:
Table<?>[] tables = ...
Field<?>[][] fields = ...
I'm assuming that your requirement is to match all tables by common column names (i.e. names that are the same as the name of the second column of the first table), in order to join them. Since you do not specify what happens if consecutive tables don't have such a match, I'm assuming you'd like to default to excluding such tables, and their columns.
In any case, I guess this is more of a question about an idea on how to do dynamic SQL with jOOQ in general, not necessarily how to solve your particular problem.
In that case, write:
Field<?> match = fields[0][1];
List<Field<?>> select = new ArrayList<>();
Table<?> from = tables[0];
select.add(fields[0][0]);
for (int i = 1; i < fields.length && i < tables.length; i++) {
if (match.getName().equals(fields[i][1].getName())) {
select.add(fields[i][0]);
from = from.join(tables[i]).on(match.eq((Field) fields[i][1]));
}
}
ctx.select(select)
.from(from)
.fetch();
If your actual requirements are very different to these assumptions, you can still ask a new question.

How to Select Random 10 records in JPQL?

I have to select random 10 records from the user table,
Below is the SQL Query which gives random 10 records.
SELECT * FROM user_table ORDER BY RANDOM() LIMIT 10
What is the JPQL alternative for this, Do we have Random() support for JPQL? is it a good practice to use RANDOM() ?
I don't know whether there is RANDOM in JPA. As an alternative solution you can use this trick :
Query queryCount = em.createQuery("SELECT COUNT(u) FROM UserTable u");
Long size = (Long) queryCount.getSingleResult();
//I use this way of Java8, you can use the way you see it better to generate random indexes
int[] index = new Random().ints(0, size, 10).toArray();
Query query = em.createQuery("SELECT u FROM UserTable u WHERE INDEX(u) IN :indexs");
^^^^^^^^^^^^^^^^^^^
query.setParameter("indexs", index);
List<UserTable> listUsersRandom = query.getResultList();
Global idea
This solution based on INDEX. The idea is:
First query - find the size of your objects
Generate a list of index between 0 and the size of your list
Second query - select the objects which is IN this generated list

Hibernate Criteria API: how to get the sum of all the values along two columns

the question is very simple but I cannot get something working.
Say, I have the following table
|....X....|.....A.....|.....B....|
|...........|.....3.....|.....2.....|
|...........|.....1.....|.....4.....|
|...........|.....1.....|.....2.....|
I simply have to obtain the total sum of values in column A and B, so (3 + 1 + 1) + (2 + 4 + 2) = 13 and I'd like to have it with Criteria API.
I tried creating a Projection summing the values along A and a DetachedCriteriawith a similar Projection summing the values along B, but I couldn't obtain a unique result from the DetachedCriteria since it doesn't expose this method.
Any advice?
You can do that with sqlProjection
.setProjection(Projections.sqlProjection("sum(A + B) as sumAB", new String[] {"sumAB"} , new Type[] {Hibernate.DOUBLE}));
https://stackoverflow.com/a/21650037/351861
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Number> q = cb.createQuery(MyEntity.class);
Root<MyEntity> t = q.from(MyEntity.class);
Path<Number> fieldB = t.get(MyEntity_.B);
Path<Number> fieldA = t.get(MyEntity_.A);
Expression<Number> sum = cb.sum(fieldA, fieldB);
q.select(sum.alias("SUM"));
System.out.println(em.createQuery(q).getSingleResult());

JPA: select random row

This is my JPA ENTITY
#Entity
#NamedQueries({
#NamedQuery(name = "Question.randQuestion", query = "SELECT q FROM Question AS q ORDER BY RANDOM")
})
#Table(name = "questions")
public class Question implements Serializable {
.....
}
The problem is:
eclipse gives me an error for this namedQuery. It says:
"The identification variable 'RANDOM' is not defined in the FROM clause"
I've tried also with RAND() instead of RANDOM and also NEWID().
Thanks.
To get a Random Row, first get list of total question and get any one.
public Question getRandomQuestion(EntityManager em) {
Query countQuery = em.createNativeQuery("select count(*) from Question");
long count = (Long)countQuery.getSingleResult();
Random random = new Random();
int number = random.nextInt((int)count);
Query selectQuery = em.createQuery("select q from Question q");
selectQuery.setFirstResult(number);
selectQuery.setMaxResults(1);
return (Question)selectQuery.getSingleResult();
}
Note: You may need to implement a logic to avoid duplicates while calling method more than once.
I had to solve a specific case of this problem where I had to select random records from a set of records matching a certain input criteria. The solution also had to support limit. I describe my solution below starting with assumptions.
Assumptions:
Given the set of criteria as input, it is possible to count number of records that match a selection criteria, as supported by the org.springframework.data.querydsl.QueryDslPredicateExecutor<T>.count(Predicate predicate) method.
Pages are zero indexed.
It is possible to request specific page as supported by the org.springframework.data.domain.PageRequest(int page, int size) method.
Algorithm
Count all records matching the input criteria.
Calculate total number of pages based on the count and specified limit.
Generate a random page index in range [0, total pages).
Request the page with index generated in previous step.
Shuffle elements in the returned page.
Code
Long totalRecords = someRepository.count(somePredicate);
Long totalPages =
(totalRecords % someLimit == 0)
? (totalRecords / someLimit)
: ((totalRecords / someLimit) + 1);
int pageIndex = (int) (Math.random() * totalPages);
PageRequest pageRequest = new PageRequest(pageIndex, someLimit);
Page<T> somePage = someRepository.findAll(somePredicate, pageRequest);
List<T> someList;
if (somePage.getTotalElements() > 0) {
someList = new ArrayList<>(somePage.getContent());
} else {
someList = new ArrayList<>();
}
Collections.shuffle(someList);
The second shuffle is to ensure records within the page are also randomized. The general case of this solution is that there is no criteria and so the count() has to be invoked with no predicate thus getting a count of all rows in the table.
As far as I understand you want to select random question from the table. You'd rather use WHERE clause, with providing some parameter from your code, like:
SELECT q FROM Question AS q WHERE id = :id
Then in the code, which creates your query you must generate random id to be selected:
query.setParam("id", getRandomId());
And to get random id, you may want to query number of rows from DB and use java.util.Random.nextInt(rowsCount) (if all ids are there, of course).
Btw, something similar is described here: http://www.shredzone.de/cilla/page/53/how-to-fetch-a-random-entry-with-hibernate.html

how to sort a column of a table in database with hibernate

I want to find 10 nearset value of a column of a table in a database to my value.
so I want to sort the value of that column, and then find 10 smaller or bigger value than my value.
how can I do this
thanks a lot for your help
HQL supports ORDER BY.
Either you do
Query q = session.createQuery("from Table order by abs(value - :v) asc";
q.setXxx("v", myValue); /* Xxx is Float or Long or Integer or... */
q.setMaxResults(10);
List<Table> l = q.list();
or
Query q1 = session.createQuery("from Table where value >= :v order by value asc";
q1.setXxx("v", myValue); /* Xxx is Float or Long or Integer or... */
q1.setMaxResults(10);
List<Table> l1 = q1.list();
Query q2 = session.createQuery("from Table where value < :v order by value desc";
q2.setXxx("v", myValue); /* Xxx is Float or Long or Integer or... */
q2.setMaxResults(10);
List<Table> l2 = q2.list();
/* now find the 10 nearest elements in Java code */
...
while (...) {
...
}
In the second example you have the inconvenience of two selects which give you 20 rows altogether and then you have to find the 10 nearest in Java code, but if there is a database index on the value column it might b a lot faster. The result will be the same for both examples.

Categories