createQueryとcreateNativeQueryは結構違う

 現在、JavaEEで作っているアプリケーションに画面を追加する事になり、それまではJPAのJPQLを使ってのcreateQueryで済んでいたのですが、今回はGROUP BYとかUNIONとかでSQLを作る必要があり、JPQLでは無理そうなのでcreateNativeQueryで実装する事にしました。
 で、最初はcreateQueryをcreateNativeQueryに置き換えてSQL文を噛ませばいいかなと思っていたのですが、どうやら結構違うらしい。。
 一つ目の違いは、createQueryならテーブル定義に沿って作ったEntityに直接入れる事が出来ますが、ちょっと複雑なSQLだと問い合わせ結果に一致したEntityを作る事自体が難しい。
 二つ目はバインド変数の違い。createQueryならバインド変数は[:PARAM]のように文字として指定して下記のように変数をセットして結果を取得できますが、

List<LoginUser> result = em.createQuery(
  "SELECT c FROM LoginUser c WHERE c.USER_TYPE < '5' AND c.STATUS_FLG < :PARAM ORDER BY c.USER_ID")
  .setParameter("PARAM", "9")
  .getResultList();

createNativeQueryでは[?]でないとダメという解りにくい相違点。。
結果的に下記のようになりました。

String SQL="SELECT KEY,SUBKEY,SUM(AMOUNT) FROM TABLE_A WHERE REGDATE = ? AND (? IS NULL OR SUBKEY = ? ) " +
		"UNION SELECT KEY,SUBKEY,SUM(AMOUNT) FROM TABLE_B WHERE REGDATE = ? AND (? IS NULL OR SUBKEY = ? ) ";

Query q = em.createNativeQuery(SQL);
for (int i = 0 ; i < 6 ; i = i + 3){
	q.setParameter(i+1, StringUtils.remove(StringUtils.remove(getDate(),"/"),":"));
	q.setParameter(i+2, getSubKey());
	q.setParameter(i+3, getSubKey());
}
List<Summary> list = new ArrayList<Summary> ();

List<Object[]> results = q.getResultList();
for (Object[] it : results) {
	Summary sum = new Summary();
	sum.setKey((String)it[0]);
	sum.setSubKey((String)it[1]);
	BigDecimal bd = (BigDecimal)it[2];
	sum.setCount((int)bd.intValue());
	list.add(sum);
}

※上記のSummaryは上記クエリ結果をセットする為だけのクラスです。

なお、数値はBigDecimalで扱うようです。
バインド変数の仕様違いにはちょっとハマりました。。

以外と知られていないが便利なHTA

 Windows用で画面一つだけとかの簡単なツールを作る場合、HTA(HTML Applications)をよく使います。かなり昔からありますが、かなりマイナーな存在のようです。筆者もその存在に気が付いたのは実は3年くらい前です。。小さい規模でしか使う事はまずないので、HTAを使うような開発を外部へ発注するような事がなかったからでしょうか?
 基本的にIE上で動作しているので、MicrosoftがIEを辞めたら終わりかも知れませんが、テキストエディタのみで作れるし、VBScriptとJavaScriptの組み合わせで大抵の事は実現できます。特に助かるのが、企業内で使う端末って勝手にソフトをインストール出来なかったり、会社によっていろんな制約があったりしますが、HTAなら端末環境上の影響がなく、Windows端末でさえあればOKという点です。少数で使うちょっとした画面を作るという前提では結構便利だと思います。