2

時間 (ミリ秒) を時間配分に変換するクエリが必要です。

私のテーブルには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 ?")

どんな助けでも大歓迎です。

4

2 に答える 2

2

function() メソッドを使用して、任意のデータベース関数を呼び出すことができます。

http://java-persistence-performance.blogspot.com/2012/05/jpql-vs-sql-have-both-with-eclipselink.htmlを参照してください。

Postgres は、グループ内で関数を使用することについてもっと不平を言っているようです。JPQL では、試すことができます。

Select mod((v.timestamp / 3600000), 24) h, count(v) from Version v group by h
于 2013-08-07T13:13:53.860 に答える
0

この問題が発生する可能性がある人のために、複雑なクエリではなく、データベースの列に基づいた回避策を見つけました。問題は、異なるベンダーのサポートが保証されていないことでした。Derby では動作しますが、MySQL では失敗します。

関心のある各メトリックごとに新しい列を作成しました。

  • 曜日
  • 時間帯 (24)

次に、ローカライズ設定とシステム時刻で初期化されたカレンダーを入力しました。

    Calendar now = Calendar.getInstance();
    now.setTimeInMillis(timestamp);
    this.year = now.get(Calendar.YEAR);
    logger.trace("Year : [{}]", year);
    this.month = now.get(Calendar.MONTH);
    logger.trace("Month : [{}]", month);
    this.weekOfYear = now.get(Calendar.WEEK_OF_YEAR);
    logger.trace("Week of Year : [{}]", weekOfYear);
    this.dayOfMonth = now.get(Calendar.DAY_OF_MONTH);
    logger.trace("Day of Month : [{}]", dayOfMonth);
    this.dayOfWeek = now.get(Calendar.DAY_OF_WEEK);
    logger.trace("Day of Week : [{}]", dayOfWeek);
    this.hourOfDay = now.get(Calendar.HOUR_OF_DAY);
    logger.trace("Hour of Day : [{}]", hourOfDay);

これが誰かに役立つことを願っています。乾杯。

于 2013-08-09T18:25:23.597 に答える