scalarSelect(cb)

概要

基本概念

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

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

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

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

実装方法

実装の流れ

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
--

Date max = memberBhv.scalarSelect(Date.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
Integer maxAvg = memberBhv.scalarSelect(Integer.class).max(new ScalarQuery<MemberCB>() {
    public void query(MemberCB subCB) {
        subCB.specify().derivedPurchaseList().avg(new SubQuery<PurchaseCB>() {
            public void query(MemberCB subCB) {
                subCB.specify().columnPurchasePrice();
            }
        }, null);
        subCB.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(new ScalarQuery<MemberCB>() {
    public void query(MemberCB subCB) {
        cb.specify().columnMemberId();
    }
}, new ScalarSelectOption().coalesce(0));

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

メソッド仕様

引数

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

戻り値

検索結果が一件もない場合は、(DBMSの関数の仕様に従って) 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 を設定すると良いでしょう。