JPQLの集計関数に価値はあるか?

まったく価値がないわけではない。次のようにHAVING句で集計関数を利用してSELECT句でエンティティを返す場合は便利だ。

select d from Department d left outer join d.employees e group by d having count(e) > 5 

Javaのコード上でもエンティティとして受け取ることができる。

String jpql = "select d from Department d left outer join d.employees e group by d having count(e) > 5";
List<Department> list = entityManager.createQuery(jpql).getResultList();


しかし、次のように集計関数をSELECT句に含める場合は便利とはいえない。Javaのコードには結果がObject配列として返されるからだ。

select d.name, count(e), avg(e.salary) from Department d  left outer join d.employees e group by d having count(e) > 5
String jpql = "select d.departmentName, count(e), avg(e.salary) from Department d left outer join d.employees e group by d having count(e) > 5";
List<Object[]> list = entityManager.createQuery(jpql).getResultList();


Object配列ではなく、DTOとして受け取るための仕組みはある。その場合はコンストラクタ式を使う(適切なコンストラクタをもつDTOをあらかじめ作成しておく必要がある)。

String jpql = "select hoge.DepartmentDto(d.departmentName, count(e), avg(e.salary)) from Department d left outer join d.employees e group by d having count(e) > 5";
List<DepartmentDto> list = entityManager.createQuery(jpql).getResultList();


集計結果をどうせDTOマッピングするならば、JPQLではなくSQLを使いその結果をDTOマッピングしてもかわらない(Kuina-Daoにはこの機能がある)。エンティティを返さないのならばJPAの特徴である永続コンテキストや遅延ローディングは意味を成さないからだ。
集計のクエリはSQLのツールで試しながらつくりたいだろうからその意味でもSQLで作成が向いているといえる。それに、集計にはRDBMS固有の構文が役立つことが多いためSQLで記述したほうが効率的だ。


JPQLはエンティティを問い合わせる言語であって、集計を扱う言語ではないだろう。