OnClause

概要

基本概念

リレーションの結合における、on 句での絞り込み条件を設定します。

例えば、"会員ステータスの表示順が 2 であること" という条件があったとして、通常の Query では、この条件は where 句に展開されます。それを、where 句ではなく、結合(join)の on 句に展開されるようにできます。この場合、検索結果は大きく異なります。

where 句
表示順が 2 のステータスに関連付く会員のみ検索対象
on 句
表示順が 2 のステータスのみが会員と結合される(会員は全て検索対象)

on 句での絞り込みは、言わば "結合時に結合先テーブルだけを絞り込む" と捉えることができます。(実行計画の内部的な挙動と一致するかどうかは別にして)

これにより、DB構造上は {n : 1} 型リレーションでも、SQL上では(一時的な) {n : 0...1} 型リレーションになります。 例えば、SetupSelect をした場合、基点テーブルの Entity は on 句で絞り込まれた関連テーブルのデータを持っていません(null になる)。

会話上では、おんくろーず と表現します。

論理削除との相性

主に、{n : 0...1} 型リレーションで関連テーブルに論理削除の概念がある場合に役に立ちます。OnClause を使えば、結合前に論理削除されているレコードを除外することができます。

InlineView でも実現可能

InlineView でも同じことが実現できます。

実装方法

実装の流れ

query().query[relation]() の後、on() を呼び出し、その後続けて、関連テーブルの Query (絞り込み条件)を実装します。

e.g. OnClauseの実装手順 (Eclipseでコード補完) {MemberStatus} @Java
MemberCB cb = new MemberCB();
cb.query().queryMemberStatus().on // .on と打って enter
--
cb.query().queryMemberStatus().on().setDisplayOrder_Equal(2);
e.g. 会員ステータスの表示順が 2 のものだけを結合 @DisplaySql
...
  from MEMBER dfloc
    left outer join MEMBER_STATUS dfrel_0
      on dfloc.MEMBER_STATUS_CODE = dfrel_0.MEMBER_STATUS_CODE
     and dfrel_0.DISPLAY_ORDER = 2

メソッド仕様

リレーションに対してのみ利用

リレーションに対してのみ利用できます。基点テーブルの Query で呼び出した場合は例外です。

他の機能との組み合わせ

他の機能との組み合わせは以下の通りです。

  • OrScopeQuery は利用可能
  • ColumnQuery は不可
  • ExistsReferrer, (Query)DerivedReferrer などのサブクエリは不可

OnClause と InlineView どちら?

OnClause だけでなく、InlineView でも同じことを実現できます。さて、どちらを使えば良いのでしょうか?

他の機能との組み合わせで若干 InlineView の方が自由度が高いため、その制約に該当する場合は、InlineView で良いでしょう。但し、そういうパターンよりも、"もうどっちでもいい" というパターンの方が多いでしょう。そういう場合はやはりパフォーマンス勝負となります。

結局は、OrScopeQuery と UnionQuery の話と同様で、そのとき実行計画を調べて速い(と思われる)方を使うに尽きます。 大抵の場合はパフォーマンス上の違いは出ないでしょう。実際に、Exampleで100万件のデータを使って幾つかのパターンを試しましたが(PostgreSQL 8.4, Oracle 10g Xe)、全く差が見られません。それでも一応、DBFluteでは、基本を OnClause に置くことをお奨めしています。万が一のインラインビューでフルスキャンが発生するリスクを考えてのことです。 また、実装がバラバラになるのも良くないというのもあるので、とにかく OnClause を基本として、パフォーマンス的な改善が見込めるようであれば InlineView というスタンスが落としどころでしょうか。