在此查询中:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> q = cb.createTupleQuery();
// FROM GamePlayedEvent gpe
Root<GamePlayedEvent> gpe = q.from(GamePlayedEvent.class);
// SELECT gameId, COUNT(*) AS count, AVG(duration)
// AS avDur, AVG(rewardCurrency) AS avCur, AVG(rewardXP) avXp
q.select(cb.tuple(
gpe.<String>get("gameId"),
cb.count(gpe).alias("count"),
cb.avg(gpe.<Double>get("duration")).alias("avDur"),
cb.avg(gpe.<Integer>get("rewardCurrency")).alias("avCur"),
cb.avg(gpe.<Integer>get("rewardXp")).alias("avXp")
));
// WHERE loginTime BETWEEN ...
q.where(cb.between(gpe.<Date>get("time"), fromTime, toTime));
// GROUP BY gameId
q.groupBy(gpe.<String>get("gameId"));
// ORDER BY count DESC
q.orderBy(cb.desc(???));
如何添加ORDER BY count DESC
,引用SELECT
子句中定义的“count”?
答案 0 :(得分:7)
如果您刚刚捕获了计数表达式并直接使用它会怎么样?
Expression event_count = cb.count(gpe);
q.select(cb.tuple(
gpe.<String>get("gameId"),
event_count,
...
));
q.orderBy(cb.desc(event_count));
答案 1 :(得分:1)
即使Pro JPA 2书中描述了别名方法可用于生成sql查询别名(第251页),但我没有成功使其无法使用EclipseLink或Hibernate。对于你的问题,我会说你的orderBy行应该是:
q.orderBy(cb.desc(cb.count(gpe));
如果它得到不同供应商的支持。
就我的研究而言,别名方法仅用于命名选择中使用的tuble中的元素(因此仅用于投影)。
我有一个问题。为什么要对此查询使用JPA Criteria API。它(查询)接缝本质上是静态的,所以为什么不使用JPQL来直接定义查询别名。
答案 2 :(得分:0)
您是否尝试使用别名设置投影?
criteria.setProjection(Projections.projectionList()
.add(Projections.count("item.id"), "countItems"));
criteria.addOrder(Order.desc("countItems"));
答案 3 :(得分:0)
我今天遇到了同样的问题,但没有一个建议的解决方案对我有用,因为我不仅需要在order by
子句中重用表达式,还需要在group by
子句中重用该表达式。
一个显而易见的解决方案是在数据库级别创建一个视图,但这有点笨拙,创建一个不必要的子查询,如果db用户没有被授予足够的权限,甚至不可能。我最终实现的一个更好的选择是编写类似这样的东西
q.select(cb.tuple(
gpe.<String>get("gameId"),
cb.count(gpe),
...
)).groupBy(cb.literal(2)).orderBy(cb.literal(2));
这种方法的第一个缺点是代码是错误的。另一个缺点是生成的sql查询包含序号位置表示法,它适用于某些数据库(如postgresql或mariadb),但不适用于其他数据库(如sql server)。然而,就我而言,我发现这是最好的选择。
在jpa 2.1上测试,hibernate 5.2.3作为提供者和postgresql 9.6。
答案 4 :(得分:0)
对于汇总字段,我有以下适用于我的代码:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<T> cq = cb.createQuery(entity);
Root<T> root = cq.from(entity);
cq.orderBy(cb.desc(cb.sum(root.get(orderByString))));
// orderByString is string entity field that is being aggregated and which we want to put in orderby clause as well.