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
Related
I´m making a DELETE FROM in HQL:
String queryText = DELETE FROM Books WHERE author = 'author1'
final Query query = getCurrentSession().createQuery(queryText);
query.executeUpdate();
How can I get the number of deleted rows in the query?
The method executeUpdate return the number of entities deleted.
So you will get the number of deleted rows (n) by the following code :
int n = query.executeUpdate();
The preparedStatement.executeUpdate() returns the number of rows affected.
For ex:
int row =preparedStatement.executeUpdate();
I use JPA to fetch the count of records from table Customer by setting the Maximum results(10).
The expectation is,
1. to receive only 10 as count If the count returned by query is greater than 10.
2. to receive the exact number of transactions if the count is equal to or less than 10
I try to achieve in the below way.
Query query = em.createQuery("SELECT COUNT(c) FROM Customer c where c.countryId ='Canada' and c.lanuguage ='ENG'");
query.setMaxResults(10);
long customerCount = (Long)query.getSingleResult();
But I am not getting the result as expected. When the query results is 100 ( I mean more than 10), then I could see 100 is being returned by the query.
Can anyone please advise me If something is incorrect in my approach?
OR
Is it not possible to achieve this in single query?
OR
Any other best way to achieve this?
Thanks in adavance
You are getting COUNT so why you are using max result ?
Your result will be always single result as it will be a number of Customers COUNT?
Your code should be next if you want to get the total count
Query query = em.createQuery("SELECT COUNT(c) FROM Customer c WHERE c.countryId ='Canada' AND c.lanuguage ='ENG'");
long customerCount = (Long)query.getSingleResult();
UPDATE
AND If you just want to get 10 as a maximum total count if COUNT result than
10 else you will got the real COUNT result, so please try next
Query query = em.createQuery("SELECT CASE WHEN COUNT(c) > 10 THEN 10 ELSE COUNT(c) END FROM Customer c WHERE c.countryId ='Canada' AND c.lanuguage ='ENG'");
int customerCount = (Integer)query.getSingleResult();
Or if you need it in logn type you can add l to number, for example 10l like in next query (NOTE: in next query 10l is not 101 but 10 in long type)
Query query = em.createQuery("SELECT CASE WHEN COUNT(c) > 10l THEN 10l ELSE COUNT(c) END FROM Customer c WHERE c.countryId ='Canada' AND c.lanuguage ='ENG'");
long customerCount = (Long)query.getSingleResult();
Anyway you can use maximum result if you want to get list of customer ids for example (assuming customer has id property with type Integer)
Query query = em.createQuery("SELECT c.id FROM Customer c WHERE c.countryId ='Canada' AND c.lanuguage ='ENG'");
query.setMaxResults(10);
List<Integer> customersIds = query.getResultList();
Suppose you have a following JPA query:
select car.year, car.month, count(car) from Car car group by car.year, car.month
Before we query for results, we need to know how many records this query will return (for pagination, UI and so on). In other words we need something like this:
select count(*) from
(select car.year, car.month, count(car)
from Car car group by car.year)
But JPA/EclipseLink does not support subqueries in "from" clause. It there a way around it?
(Of course you can use plain SQL and native queries, but this is not an option for us)
A portable JPA solution:
select count(*) from Car c where c.id in
(select MIN(car.id) from Car car group by car.year, car.month)
You could also go with something like:
select COUNT(DISTINCT CONCAT(car.year, "#", car.month)) from car
but I expect this to be less performant due to operations with textual values.
What about:
select count(distinct car.year) from car
I have another approach to solve this issue . by using my approach you don't need to know the no of rows this query is going to return.
here it is your solution :-
you going to need two variables
1) pageNo (your page no should be 1 for first request to data base and proceeding request it should be incremental like 2 ,3 , 4 5 ).
2) pageSize.
int start = 0;
if(pageNo!=null && pageSize!=null){
start = (pageNo-1) * pageSize;
}else{
pageSize = StaticVariable.MAX_PAGE_SIZE; // default page size if page no and page size are missing
}
your query
em.createquery("your query ")
.setfirstResult(start)
.setMaxResult(pageSize)
.getResultList();
As #chris pointed out EclipseLink supports subqueries. But the subquery can't be the first one in the from-clause.
So I came up with the following workaround which is working:
select count(1) from Dual dual,
(select car.year, car.month, count(car)
from Car car group by car.year) data
count(1) is important as count(data) would not work
You have to add an entity Dual (If your database does not have a DUAL table, create one with just one record.)
This works but I still consider it a workaround that would only work if you allowed to create the DUAL table.
Simply you can use setFirstResult and setMaxResult to set record bound for query ,also use size of list to return count of records that query runs. like this :
Query query = em.createQuery("SELECT d.name, COUNT(t) FROM Department d JOIN
d.teachers t GROUP BY d.name");
//query.setFirstResult(5);
//query.setMaxResult(15); this will return 10 (from 5 to 15) record after query executed.
List<Object[]> results = query.getResultList();
for (int i = 0; i < results.size(); i++) {
Object[] arr = results.get(i);
for (int j = 0; j < arr.length; j++) {
System.out.print(arr[j] + " ");
}
System.out.println();
}
-----Updated Section------
JPA does not support sub-selects in the FROM clause but EclipseLink 2.4 current milestones builds does have this support.
See, http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#Sub-selects_in_FROM_clause
You can probably rewrite the query with just normal joins though.
Maybe,
Select a, size(a.bs) from A a
or
Select a, count(b) from A a join a.bs b group by a
I hope this helps you.
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
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.