we know hibernate has this in clause:
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.in(userIds));
Is there any limit on the size of userIds (which is an ArrayList, say)?
Thanks
It actually depends on the particular database you use. For example in Oracle this limit is 1000.
If you need to pass more values you need to use another approach. For example put the values into a temporary table and then do a select where id in (select id from temptable) query.
Related
I have an instance of JPAQuery<?> and need to retrieve the count. However, since the table may contain many items (millions), I want to limit the count to a given maximum, say 50,000.
The current QueryDSL-Code effectively does this:
query.fetchCount();
Now my desired modifications are quite trivial in raw sql:
select count(*) from (<whatever query> limit 50000);
However, I do not know how I would express this in querydsl. The following code is not correct, because .from() takes an entity path, but query is a query:
JPAExpressions.select(Wildcard.all)
.from(query.limit(50000))
.fetchCount();
I am using querydsl 4.
JPAExpressions.select(Wildcard.all) returns a child of SimplyQuery, which you can call limit on.
JPAExpressions.select(Wildcard.all)
.from(entity)
.limit(50000)
.fetchCount();
I have to execute below query through JDBC call
select primaryid from data where name in ("abc", adc", "anx");
Issue is inside in clause I have to pass 11000 strings. Can I use prepared statement here? Or any other solution any one can suggest. I dont want to execute the query for each record, as it is consuming time. I need to run this query in very less time.
I am reading the strings from an XML file using DOMParser. and I am using sql server db.
I'm just wondering why you would need to have a manual set of 11,000 items where you need to specify each item. It sounds like you need to bring the data into a staging table
(surely it's not been selected from the UI..?), then join to that to get your desired resultset.
Using an IN clause with 11k literal values is a really bad idea - off the top of my head, I know one major RDBMS (Oracle) that doesn't support more than 1k values in the IN list.
What you can do instead:
create some kind of (temporary) table T_NAMES to hold your names; if your RDBMS doesn't support "real" (session-specific) temporary tables, you'll have to add some kind of session ID
fill this table with the names you're looking for
modify your query to use the temporary table instead of the IN list: select primaryid from data where name in (select name from T_NAMES where session_id = ?session_id) or (probably even better) select primaryid from data join t_names on data.name = t_names.name and t_names.session_id = ?session_id (here, ?session_id denotes the bind variable used to pass your session id)
A prepared statement will need to know the number of arguments in advance - something along the lines of :
PreparedStatement stmt = conn.prepareStatement(
"select id, name from users where id in (?, ?, ?)");
stmt.setInt(1);
stmt.setInt(2);
stmt.setInt(3);
11,000 is a large number of parameters. It may be easiest to use a 'batch' approach as described here (in summary - looping over your parameters, using a prepared statement
each time)
Note - if your 11,000 strings are the result of an earlier database select, then the best approach is to write a stored procedure to do the whole calculation in the database (avoiding passing the 11,000 strings back and forth with your code)
You can merge all your parameter strings into one bitg string separating by ';' char
bigStrParameter=";abc;adc;anx;"
And use LOCATE to find substring.
select primaryid from data where LOCATE(concat(';',name,';'),?)>=0;
I want to insert foreign key of one table in another on basis of certain criteria. Structure is like
insert into CustomerResult(customer,draw) select c.idCustomer, from Customer c,Draw d where ..... and c.idCustomer in (select cc.idCustomer from Customer cc where ..... limit 10)
here i want to insert only fix no of records which fulfill certain criteria. I know hql has no limit keyword but want to implement like this. any suggestion?
I don't think that what you want to do (use limit in subquery) is directly supported by Hibernate. Have a look at these previous answers:
How to set a limit to inner query in Hibernate?
How do you do a limit query in HQL?
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().
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!
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.
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.
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.
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.
The answer by #PSV Bhat is difficult if you are dynamically generating your Criteria. Here is a solution that extends hibernate Order class:
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
private void addOrderByToCriteria(Criteria criteria) {
criteria.addOrder(Order.asc("foobar"));
criteria.addOrder(ORDER_RANDOM);
}
private static final OrderRandom ORDER_RANDOM = new OrderRandom();
private static class OrderRandom extends Order {
public OrderRandom() {
super("", false);
}
#Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
return "RANDOM()"; // or RAND() or whatever this is in your dialect
}
}