views:

618

answers:

4

I can't figure out how to fetch n random rows from a criteria instance:

Criteria criteria = session.createCriteria(Table.class);
criteria.add(Restrictions.eq('fieldVariable', anyValue));
...

Then what? I can't find any doc with Criteria API

Does it mean I should use HQL instead?

Thanx!

EDIT: I get the number of rows by:

int max = criteria.setProjecxtion(Projections.rowCount()).uniqueResult();

How do I fetch n random rows with indexes between 0 and max? Thx again!

A: 

You can not fetch random rows efficiently, sorry. Hibernate can only do what SQL does, and random row fetch simply is not part of any standard SQL implementation I know - actually it is to my knowledge not part of ANY SQL that I am aware of (anyone please enlight me).

And as Hibernate is an O/R mapper, and not a wonder machine, it can only do what the underlying database supports.

If you have a known filed with ascending numbers and know start and end, you can generate a random number on the computer and ask for that row.

TomTom
+1  A: 

The Criteria API doesn't offer facilities for this. In MySQL however, you can use ORDER BY RAND() LIMIT n for this where n represents the number of random rows you'd like to fetch.

SELECT col1, col2, col3 FROM tbl ORDER BY RAND() LIMIT :n

You indeed need to execute it as HQL.

BalusC
+1  A: 

First of all, be aware that there is no standard way to do this in SQL, each database engine uses its own proprietary syntax1. With MySQL, the SQL statement to get 5 random rows would be:

SELECT column FROM table
ORDER BY RAND()
LIMIT 5

And you could write this query in HQL because the order by clause in HQL is passed through to the database so you can use any function.

String query = "SELECT e.attribute FROM MyEntity e ORDER BY RAND()";
Query q = em.createQuery(query);
q.setMaxResults(5);

However, unlike HQL, the Criteria API currently doesn't support ORDER BY Native SQL (see HHH-2381) and in the current state, you would have to subclass the Order class to implement this feature. This is doable, refer to the Jira issue, but not available out of the box.

So, if really you need this query, my recommendation would be to use HQL. Just keep in mind it won't be portable.

1 Other readers might want to check the post SQL to Select a random row from a database table to see how to implement this with MySQL, PostgreSQL, Microsoft SQL Server, IBM DB2 and Oracle.

Pascal Thivent
+1  A: 

Actually it is possible with Criteria and a little bit of tweaking. Here is how:

Criteria criteria = session.createCriteria(Table.class);
criteria.add(Restrictions.eq('fieldVariable', anyValue));
criteria.add(Restrictions.sqlRestriction("1=1 order by rand()"));
criteria.setMaxResults(5);
return criteria.list();

any Restrictions.sqlRestriction will add keyword 'and'; so to nullify its effect, we shall add a dummy condition and inject our rand() function.

PSV Bhat
That was convenient and helped me!
Nischal