SQL関数フィルタ
概要
基本概念
子テーブルの導出カラム(最大値や合計値)などの値を、SQL関数を利用してSQL上でフィルタ処理を施すことができます。 主にSQL上で利用が完結するような値をフィルタするのに有効です。
SQL関数フィルタの仕様は、以下の全ての機能で共通しています。
- (Specify)DerivedReferrer
- 子テーブルの導出カラムの取得
- (Query)DerivedReferrer
- 子テーブルの導出カラムで絞り込み
- ColumnQuery
- カラム同士の絞り込み条件
それぞれの機能のオプション指定にて利用できます。
e.g. 最終ログイン日時が null の場合は 1192-01-01 として扱う {MEMBER_LOGIN} @Java
cb.query().derivedMemberLoginList().max(new SubQuery<MemberLoginCB>() {
public void query(MemberLoginCB subCB) {
subCB.specify().columnLoginDatetime();
subCB.query().setMobileLoginFlg_Equal_False();
}
}, Member.ALIAS_..., new DerivedReferrerOption().coalesce("1192-01-01"));
関数スタイル
具体的なSQL関数を意識したスタイルのメソッドが用意されています。
coalesce()
null の場合のデフォルト値を指定できます(@since 0.9.7.4)。DerivedReferrerの導出値などで利用する集計関数(max(), avg() など)は、計算対象レコードが存在しない場合に null を戻す可能性があります。特に (Query)DerivedReferrer のようなSQL上で導出値の利用が完結するような場合には、null だと条件式の結果が業務とは都合の合わないことがあるため、coalesce() 関数を使って null の場合に 0 として計算させたりすると良いでしょう。
e.g. 合計購入価格を導出する際に、そもそも購入したことのない会員は 0 に @Java
cb.query().derivedPurchaseList().max(new SubQuery<PurchaseCB>() {
public void query(PurchaseCB subCB) {
subCB.specify().columnPurchasePrice();
}
}, Member.ALIAS_..., new DerivedReferrerOption().coalesce(0));
様々な型が想定されるため引数は Object 型です。バインド変数として扱われます。
round()
指定された精度で(主に数値を)丸めます。SQL上では round 関数が利用されます。厳密な丸め仕様はDBMSに依存します。基本的には数値型を想定していますが、日付型に対して round 関数が利用できるDBMSの場合は、引数に指定できる値はそのDBMSの round 関数の仕様に依存します。
DBMS ごとの違いに対応できるように引数は Object 型です。バインド変数として扱われます。
trunc()
指定された精度で切り捨てします。SQL上では trunc 関数が利用されます。DBMSごとの関数名の違いは内部的に吸収されます。基本的には数値型を想定していますが、日付型に対して trunc 関数が利用できるDBMSの場合は、引数に指定できる値はそのDBMSの trunc 関数の仕様に依存します。
DBMS ごとの違いに対応できるように引数は Object 型です。バインド変数として扱われます。
別途、目的スタイルの切り捨てメソッド(truncDay() や truncTime() など)が存在しますので、切り捨ての目的が合う場合はそちらを利用すると良いでしょう。
目的スタイル
関数は問わず、目的を意識したスタイルのメソッドが用意されています。 どのようなSQL関数を使って解決するかは、DBFluteが内部的に解決します。
(DBFluteとして)正式サポートされていない DBMS では、これら機能もサポートされない可能性があります。 また、正式サポートされている DBMS でも、そもそもSQL関数で実現できない、もしくは、独自性の強いSQL関数の仕様を持っている DBMS の場合はサポートされないパターンがありますので、利用する際は必ず単体テストなどでの事前検証をお奨めします。
日付の切り捨て
例えば、時分秒を切り捨てるなど、日付に対する切り取りをします(@since 0.9.8.6)。
- truncMonth()
- 月、日、時分秒ミリ秒を切り捨て (年初めになる)
- truncDay()
- 日、時分秒ミリ秒を切り捨て (月初めになる)
- truncTime()
- 時分秒ミリ秒を切り捨て (その日の始まりになる)
引数はありません。また、二度呼び出しは許されません。
e.g. 右辺カラムの日時に対して時分秒ミリ秒を切り捨て @Java
...
cb.columnQuery(new SpecifyQuery<MemberCB>() {
public void specify(MemberCB cb) {
cb.specify().columnBirthdate();
}
}).greaterThan(new SpecifyQuery<MemberCB>() {
public void specify(MemberCB cb) {
cb.specify().columnFormalizedDatetime();
}
}).convert(new ColumnConversionOption().truncTime());
日付の加算
例えば、一日進めるなど、日付に対する加算をします(@since 0.9.8.6)。
- addYear()
- "年" を進める (もしくは戻す)
- addMonth()
- "月" を進める (もしくは戻す)
- addDay()
- "日" を進める (もしくは戻す)
- addHour()
- "時" を進める (もしくは戻す)
- addMinute()
- "分" を進める (もしくは戻す)
- addSecond()
- "秒" を進める (もしくは戻す)
引数はそれぞれ Integer 型を指定します。マイナス値を指定すると減算になります。また、null を指定すると無効な呼び出しとして何も処理されません。二度呼び出しは許されません。
e.g. 右辺カラムの日時に対して 1 日進める @Java
...
cb.columnQuery(new SpecifyQuery<MemberCB>() {
public void specify(MemberCB cb) {
cb.specify().columnBirthdate();
}
}).greaterThan(new SpecifyQuery<MemberCB>() {
public void specify(MemberCB cb) {
cb.specify().columnFormalizedDatetime();
}
}).convert(new ColumnConversionOption().addDay(1));