我需要一个查询来将时间(毫秒)转换为每小时分布。
我的表有一个名为时间戳的列:以毫秒为单位的值。要按小时分组,我需要按 1000 -> 秒按 3600 -> 小时 -> mod 24 -> 获取创建记录的时间。
时间戳很长:
public static volatile SingularAttribute<VersionJpa, Long> timestamp;
然后我可以在日分布中显示结果。但是,这不起作用,组不工作,我得到的完整列表没有分组,也没有计算在内。
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<VersionJpa> root = cq.from(VersionJpa.class);
cq.where(p);
Expression<Integer> group = cb.mod(cb.toInteger(cb.quot(root.get(VersionJpa_.timestamp), 3600000)),24);
cq.multiselect(group, cb.count(root));
cq.groupBy(group);
TypedQuery<Tuple> tq = em.createQuery(cq);
return tq.getResultList();
此 SQL (mysql) 生成正确的结果。JPA有同等的楼层吗?试过了。(整数)|| toInteger()
select mod(floor(stamp/3600000), 24) , count(*) from versions group by mod(floor(stamp/3600000), 24);
我发现在单元测试期间(在 Derby 上)它运行良好,但在像 setup(MySQL)这样的更多生产环境中,它不会将最内部的聚合转换为整数,因此该组是在浮动值上完成的,而不是在 24(0 , 1, .. 23) 潜在值(返回千组)。
Expression<Integer> hours = cb.mod(cb.quot(root.get(VersionJpa_.timestamp).as(Integer.class), 3600000).as(Integer.class),24).as(Integer.class);
cq.multiselect(hours, cb.count(root));
cq.groupBy(hours);
添加 PostgreSQL 支持和测试会导致另一个错误,这使我认为我的查询是错误的:
RuntimeException Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: org.postgresql.util.PSQLException: ERROR: column "versions.stamp" must appear in the GROUP BY clause or be used in an aggregate function Position: 13 Error Code: 0 Call: SELECT MOD((STAMP / ?), ?), COUNT(ID) FROM VERSIONS GROUP BY MOD((STAMP / ?), ?) LIMIT ? OFFSET ? bind => [6 parameters bound] Query: TupleQuery(referenceClass=VersionJpa sql="SELECT MOD((STAMP / ?), ?), COUNT(ID) FROM VERSIONS GROUP BY MOD((STAMP / ?), ?) LIMIT ? OFFSET ?")
任何帮助表示赞赏。