selectScalar(cb)

概要

基本概念

ConditionBeanをもとにスカラ検索 をします。

例えば、"一番若い会員の生年月日"、"全体の購入価格の平均" など、あるカラムの導出値を ConditionBean の絞り込み条件をもとに取得することができます。

スカラ値の取得ではなく、スカラ値を使ってSQL内で絞り込み条件をする、というような場合は、ScalarCondition という別の機能になります。(取得ではなく単なる絞り込み条件なので)

会話上では、せれくとすから と表現します。

実装方法

実装の流れ ※1.1.x (Java8版)

Behaviorの selectScalar() を呼び出し、受け取るスカラ値のプログラム型を引数に指定します。続けて、関数メソッドを呼び出し、ConditionBean で絞り込みを指定するコールバックを引数に指定します。

e.g. scalarSelect()の実装手順 (Eclipseでコード補完) {MEMBER} @Java
memberBhv.selSca // .selSca と打って enter
--

memberBhv.selectScalar(resultType);
--

// 引数に受け取るスカラ値のプログラム型を指定し、
// max() や min()、sum() などの関数メソッドを選んで enter
//  => max(), min(), sum(), avg()
memberBhv.selectScalar(LocalDate.class).ma
--

// メソッドが補完されて、引数の "cbLambda" が選択状態に
memberBhv.scalarSelect(LocalDate.class).max(cbLambda)
--

// cbLambdaの部分で、_ll (補完テンプレートが有効なら)
memberBhv.selectScalar(LocalDate.class).max(_ll)
--

// Lambda引数名はcbにして...
// ScalarQuery のConditionBeanで導出カラムと絞り込み条件を指定
memberBhv.selectScalar(LocalDate.class).max(cb -> {
    cb.specify().columnBirthdate(); // 生年月日の最大値
    cb.query().setMemberStatusCode_Equal_Formalized(); // 正式会員に限る
})
--

memberBhv.selectScalar(LocalDate.class).max(cb -> {
    cb.specify().columnBirthdate();
    cb.query().setMemberStatusCode_Equal_Formalized();
}); // セミコロン ';' を打って ctrl(or command) + 2 そして L
--

// どん!
// (もしくは、ifPresent()やalwaysPresent()を使って、チェーンで戻り値を扱うでもOK)
OptionalScalar<LocalDate> maxDate = memberBhv.selectScalar(LocalDate.class).max(cb -> {
    cb.specify().columnBirthdate();
    cb.query().setMemberStatusCode_Equal_Formalized();
});
e.g. 正式会員における、生年月日の最大値を取得 @DisplaySql
select max(dfloc.BIRTHDATE) as dfscalar
  from MEMBER dfloc 
 where dfloc.MEMBER_STATUS_CODE = 'FML'

実装の流れ ※1.0.x (Java6版)

Behaviorの scalarSelect() を呼び出し、受け取るスカラ値のプログラム型を引数に指定します。続けて、関数メソッドを呼び出し、ConditionBean で絞り込みを指定するコールバックを引数に指定します。

※DBFlute-1.1より、selectScalar() という名前になっています。

e.g. scalarSelect()の実装手順 (Eclipseでコード補完) {MEMBER} @Java
memberBhv.sc // .sc と打って enter
--

memberBhv.scalarSelect(resultType);
--

// 引数に受け取るスカラ値のプログラム型を指定し、
// max() や min()、sum() などの関数メソッドを選んで enter
//  => max(), min(), sum(), avg()
memberBhv.scalarSelect(Date.class).ma
--

// メソッドが補完されて、引数の "scalarQuery" が選択状態に
memberBhv.scalarSelect(Date.class).max(scalarQuery)
--

// "new " (new + 空白一つ) と打って ctrl + space そして enter
memberBhv.scalarSelect(Date.class).max(new )
--

// 実装メソッドの空実装が自動生成される (Eclipse-3.5 以上)
memberBhv.scalarSelect(Date.class).max(new ScalarQuery<MemberCB>() {
    
    public void query(MemberCB cb) {
        // TODO Auto-generated method stub
        
    }
})
--

// ctrl (or command) + D で不要な空行やTODOコメントを消して
// ScalarQuery のConditionBeanで導出カラムと絞り込み条件を指定
memberBhv.scalarSelect(Date.class).max(new ScalarQuery<MemberCB>() {
    public void query(MemberCB cb) {
        cb.specify().columnBirthdate(); // 生年月日の最大値
        cb.query().setMemberStatusCode_Equal_Formalized(); // 正式会員に限る
    }
}); // セミコロン ';' を打って ctrl(or command) + 2 そして L
--

LocalDate max = memberBhv.scalarSelect(LocalDate.class).max(new ScalarQuery<MemberCB>() {
    public void query(MemberCB cb) {
        cb.specify().columnBirthdate(); // 生年月日の最大値
        cb.query().setMemberStatusCode_Equal_Formalized(); // 正式会員に限る
    }
});
e.g. 正式会員における、生年月日の最大値を取得 @DisplaySql
select max(dfloc.BIRTHDATE) as dfscalar
  from MEMBER dfloc 
 where dfloc.MEMBER_STATUS_CODE = 'FML'

子テーブルの導出カラム

導出カラムとして、子テーブルの導出カラムを指定することもできます。 ScalarSelect の中で (Specify)DerivedReferrer を利用します。(@since 0.9.7.7)

e.g. それぞれの会員の平均購入価格の会員全体での最大 @Java
OptionalScalar<Integer> maxAvg = memberBhv.scalarSelect(Integer.class).max(cb -> {
    cb.specify().derivedPurchaseList().avg(purchaseCB -> {
        purchaseCB.specify().columnPurchasePrice();
    }, null);
    cb.query().set...
});
e.g. それぞれの会員の平均購入価格の会員全体での最大 @DisplaySql
select max((select avg(sub1loc.PURCHASE_PRICE)
              from PURCHASE sub1loc 
             where sub1loc.MEMBER_ID = dfloc.MEMBER_ID
       )) as dfscalar
  from MEMBER dfloc 
 where ...

導出値をSQL関数でフィルタ

導出値をSQL関数でフィルタすることができます。関数メソッドのオーバーロードの第二引数である ScalarSelectOption にて、そのフィルタ処理を指定することができます。@since 0.9.8.4

e.g. 集計対象レコードが一件も存在しなかった場合に null ではなく 0 を戻す @Java
Integer maxValue = memberBhv.scalarSelect(Integer.class).max(cb -> {
    cb.specify().columnMemberId();
}, op -> op.coalesce(0));

もろもろの仕様は DerivedReferrer における DerivedReferrerOption と基本的に同じです。

メソッド仕様

引数

スカラ値のプログラム型、および、サブクエリは必須です。

戻り値

OptionalScalar型です。

検索結果が一件もない場合は、(DBMSの関数の仕様に従って) Optional が empty になることがあります。 coalesce()関数などを使うことで、nullがなくなるようにすることもできます。

導出カラムの指定

ScalarQuery 内での導出カラムは、必ず一つだけ指定します。 また、基点テーブルのカラム、もしくは、子テーブルの導出カラムのどちらかに限ります。 (カラム指定がない、もしくは、二つ以上のカラムが指定された場合は例外)

利用できる関数

利用できる関数は以下の通りです。

max()
最大値。計算対象データが無い場合は null となる。
min()
最小値。計算対象データが無い場合は null となる。
sum()
合計値。数値のみ。計算対象データが無い場合は null となる。 受け取るプロパティの型がカラムに対応する型だと、(合計値なので)オーバーフローする可能性もあるので、業務的な可能性を踏まえてサイズの大きい型(Long や BigDecimal など)を利用すると良い。
avg()
平均値。数値のみ。計算対象データが無い場合は null となる。値が小数点になる可能性があるので、受け取るプロパティの型を小数点を扱える型(BigDecimal など)にすると良い。
count()
レコード数。数値のみ。計算対象データが無い場合は 0 となる。selectCount(cb) と同じである。
countDistinct()
種類数。数値のみ。計算対象データが無い場合は 0 となる。

ConditionBeanは絞り込み条件のみ

ScalarQuery の ConditionBean は、絞り込み条件だけの指定に利用するものです。 SetupSelect や OrderBy など絞り込み条件とは関係のない機能は呼び出してはいけません。

オーバーライド

selectList() と同じような要領となります。

UnionQuery での select 句のカラム

PKが存在するテーブルの場合で、引数の ConditionBean で UnionQuery を利用すると、UnionQuery に対応する select 句は PK カラムと導出カラムのみ列挙されます。 つまり、CLOB や TEXT 型のカラムが含まれるテーブルで、union の distinct 処理でそれらカラムがサポートされない DBMS でも問題なく UnionQuery を利用することができます(@since 0.9.7.7)

旧バージョン、および、PKなしテーブル(ビューも含む)では、バージョンに関わらず回避はできません。ビューにおいては、AdditionalPrimaryKey で疑似の PK を設定すると良いでしょう。