问题
I want to convert my sql query from SQL to CriteriaQuery, I have this sql query:
1)
SELECT * FROM table AS t WHERE id = (SELECT MAX(id) FROM table AS t WHERE t.element_id = 354 AND (name <> 'foo' OR (name = 'bar' AND event = 'foo')));
2)
SELECT tr1.*
FROM table AS tr1
INNER JOIN (SELECT MAX(id) AS id FROM table AS tr WHERE tr.element_id = 354 AND (name <> 'foo' OR (name = 'bar' AND event = 'foo'))) AS tr2
ON tr1.id = tr2.id;
How is the best way to do this ?
public Predicate createsubqueryDateGreaterThanTest(CriteriaBuilder cb, Root<? extends Entity> root, Date inputDate){
// create the outer query
CriteriaQuery<Date> cq = cb.createQuery(Date.class);
Root<Table> rootQuery = cq.from(Table.class);
Subquery<Table> sub = cq.subquery(Table.class);
Root<Table> subRoot = sub.from(Table.class);
//sub.select(subRoot);
cq.multiselect(rootQuery);
sub.select(subRoot)
//cq.multiselect(rootQuery.select(cb.max(Table_.elementId)));
//sub.select(cb.greatest(cb.get(Entity_.element).get("id")));
//cq.multiselect(subRoot.select(cb.greatest(Table_.elementId)))
.where(
cb.greaterThanOrEqualTo(subRoot.get(Table_.date), inputDate),
cb.equal(root.get(Entity_.element).get("id"), subRoot.get(Table_.elementId)),
cb.notEqual(subRoot.get(Table_.name), "foo"),
cb.or(
cb.equal(subRoot.get(Table_.name), "bar"),
cb.and(cb.equal(subRoot.get(Table_.event), 'foo'))
)
);
return cb.exists(sub);
}
The query runs but the result is incorrect.
回答1:
From what I remember this should be the representation of your 1st query.
Edit: Tested nowI can not test it right now, as my database is not responding, so if it does not work I'll edit the answer later.
Use ParameterExpression's for non constant parameters to make sure that the server can reuse the query. Else it need to analyze and replan every new query it receives.
But in this case ParamterExpression's do not seem to work correctly, might be an Hibernate issue (I used 5.4.2.Final for testing this).
Ps.: You should avoid using 'sql' keywords for table identifiers, so instead of naming your table 'table' use something else.
SELECT * FROM table AS t WHERE id = (SELECT MAX(id) FROM table AS t WHERE t.element_id = 354 AND (name <> 'foo' OR (name = 'bar' AND event = 'foo')));
CriteriaQuery<Table> criteriaQuery = cb.createQuery(Table.class);
Root<Table> root = criteriaQuery.from(Table.class);
Subquery<Integer> sub = criteriaQuery.subquery(Integer.class);
Root<Table> subRoot = sub.from(Table.class);
criteriaQuery.where(
cb.equal(subRoot.get(Table_.element_id), 354),
cb.or(cb.notEqual(subRoot.get(Table_.name), "foo"),
cb.and(cb.equal(subRoot.get(Table_.name), "bar"),
cb.equal(subRoot.get(Table_.event), "foo"))));
sub.select(cb.max(subRoot.get(Table_.id)));
criteriaQuery.where(cb.equal(root.get(Table_.id), sub));
criteriaQuery.select(root);
List<Table> result =
entityManager.createQuery(criteriaQuery)
.getResultList();
来源:https://stackoverflow.com/questions/56233604/how-to-convert-sql-query-using-criteriaquery