時間 (ミリ秒) を時間配分に変換するクエリが必要です。
私のテーブルにはtimestampという列があります:ミリ秒の値。時間でグループ化するには、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 での) 単体テスト中、これはうまく動作することがわかりましたが、セットアップ (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 ?")
どんな助けでも大歓迎です。