[seasar-dotnet:1869] Re: [DBFlute.NET]業務的one-to-oneな条件に他テーブルのカラム値指定

kubo [E-MAIL ADDRESS DELETED]
2010年 10月 12日 (火) 03:28:33 JST


久保(jflute)です。

fpさん、お気遣いありがとうございます。
まあ、業務的one-to-oneもこれだけ使われれば喜ぶと思うので。
(他ではなかなか無いDBFluteらしい機能でもあるし)

そして、ひとまず Java の方では落ち着きました。
LocalTable や ForeignTable を指定するときは、
$localTable、$foreignTable というように定数指定にし、
ReferrerTable の時だけテーブル名そのままにしました。
(そうすることで、もっと曖昧さがなくなるかと)

; FK_MEMBER_MEMBER_LOGIN_FOREIGN_FOREIGN_OVER_TEST = map:{
    ; localTableName  = MEMBER    ; foreignTableName  = MEMBER_LOGIN
    ; localColumnName = MEMBER_ID ; foreignColumnName = MEMBER_ID
    ; fixedCondition =
 $$over($localTable.memberStatus)$$.DISPLAY_ORDER
        = $$over($foreignTable.memberStatus)$$.DISPLAY_ORDER
    ; fixedSuffix = AsForeignForeignOverTest
}

そして、$foreignTable を指定すると、
以下のようなSQLに自動解決されます。

  from member dflocal
    left outer join member_status dfrelation_0 on
dflocal.MEMBER_STATUS_CODE = dfrelation_0.MEMBER_STATUS_CODE
    left outer join (select dffixedbase.*, dffixedjoin_0_0.DISPLAY_ORDER
                       from member_login dffixedbase
                         left outer join member_status dffixedjoin_0_0
on dffixedbase.LOGIN_MEMBER_STATUS_CODE =
dffixedjoin_0_0.MEMBER_STATUS_CODE
                    ) dfrelation_4
      on dflocal.MEMBER_ID = dfrelation_4.MEMBER_ID
     and dfrelation_0.DISPLAY_ORDER = dfrelation_4.DISPLAY_ORDER

$foreignTableの後ろのDISPLAY_ORDERをパースして
取り出して、インラインビューの select 句に指定しています。
MEMBER_LOGINに同名のカラムがあるとだめですが、
"select * " をするよりかは遥かにバッティングの可能性は減るかと。
(オプションのような形式でエリアス名を指定する拡張を
後で入れようと思えば入れられるような構造になっています)

一旦、この段階でDBFlute.NETの方への移植をします。
(結構、たくさん修正しているのである程度時間掛かります)

ちなみに、上記の $foreignTable のインラインビュー方式を
fpさんの業務で活用することはできますでしょうか?

2010/10/12 fp <[E-MAIL ADDRESS DELETED]>:
> fpです。
>
> 久保さん、ありがとうございます。
>
> 無理のない範囲で宜しくお願いします。
> (既に大抵無理言ってしまってますが)
>
> (2010/10/12 1:03), kubo wrote:
>> 久保(jflute)です。
>>
>>> 私の想定するSQLは単純に以下の通りです。
>>>
>>> select ...
>>>   from MEMBER dflocal
>>>     left outer join MEMBER_LOGIN dfrelation_4
>>>       on dflocal.MEMBER_ID = dfrelation_4.MEMBER_ID
>>>     left outer join MEMBER_STATUS dfrelation_4_1
>>>       on dfrelation_4.LOGIN_MEMBER_STATUS_CODE =
>>> dfrelation_4_1.MEMBER_STATUS_CODE
>>>      and dfrelation_4_1.DISPLAY_ORDER = 2
>>
>> なるほど、MEMBER_LOGIN の自体の on 句に入るのではなく、
>> その先のMEMBER_STATUS の on 句に指定した条件を入れる
>> イメージでしたか。で、そのように条件付けると、
>> 業務的には MEMBER からone-to-oneになると。
>>
>> fixedConditionは、現状ではMEMBER_LOGIN の join の on 句の
>> 条件を指定することが大前提となっていますので、その土台のまま
>> ではそのようなSQLは作ることはできません。
>> なので、実現するには MEMBER_STATUS の on 句の方に
>> 指定できるような新しい仕組みが必要ですね。
>> 考えられるのが以下のパターン:
>>
>> A. MEMBER_LOGIN の on 句に条件を入れるパターン(通常)
>> B. MEMBER_STATUS の on 句に条件を入れるパターン(新)
>> C. 両方の on 句に条件を入れるパターン(新)
>> D. Cに加えて、さらに先の関連テーブルにも入れるパターン(新)
>>
>> fpさんの要件では B というところですね。
>> これはこれで、ほぼ新機能と言っていいもので、
>> 特に「dfpropでどう指定させるのか」を
>> 時間掛けて練る必要がありそうです。
>> (fixedConditionに加えてoverConditionという項目を追加とか、
>> fixedConditionの中で自動判別させて条件の嫁ぎ先を決定するとか)
>>
>> とりあえずは一旦、上記以外のパターンの実装を固めて、
>> SNAPSHOT 出したいと思います。上記以外のパターンだけでも
>> 業務的one-to-oneがしっかりと使えるように。
>> (どうしても Java to C# で、ちょっとC#版が遅れるので段階的に)
>>
>> また、ひとまず以下のようなSQLが自動解決できれば、
>> それはそれで役に立ちそうなので、できるようにしてみようかと。
>> (一応、B のパターンと同じ動作になり得るかなと)
>>
>> select *
>>   from member dflocal
>>     left outer join
>>       (select MEMBER_LOGIN.*, dfrelation_4_1.DISPLAY_ORDER
>>          from MEMBER_LOGIN
>>          left outer join MEMBER_STATUS dfrelation_4_1
>>            on MEMBER_LOGIN.LOGIN_MEMBER_STATUS_CODE =
>> dfrelation_4_1.MEMBER_STATUS_CODE
>>       ) dfrelation_4
>>       on dflocal.MEMBER_ID = dfrelation_4.MEMBER_ID
>>      and dfrelation_4.DISPLAY_ORDER = 2
>>
>> dfprop において、fixedConditionの中に
>> $$over(!foreignTable!.memberStatus)$$.DISPLAY_ORDER
>> というように指定があれば、InlineViewを自動で展開して、
>> DISPLAY_ORDER だけを select 句に追加して、
>> MEMBER_LOGINのエリアス名経由でDISPLAY_ORDERが
>> 利用できるように。
>> (って書いておいてできなかったりして...一応半分くらいできてて)
>>
>> 2010/10/11 fp<[E-MAIL ADDRESS DELETED]>:
>>> fpです。
>>>
>>> 久保さん、こんばんは、ありがとうございます。
>>>
>>> 今まで良く分かっていなかったのですが、
>>> このレスで何となく久保さんの仰る曖昧さの意味が
>>> 分かったような気がします。
>>> ほんと申し訳ありません。
>>>
>>> 「二つの left outer join が、互いに参照し合う」
>>> というのが問題ですね。
>>>
>>> 私の想定するSQLは単純に以下の通りです。
>>>
>>> select ...
>>>   from MEMBER dflocal
>>>     left outer join MEMBER_LOGIN dfrelation_4
>>>       on dflocal.MEMBER_ID = dfrelation_4.MEMBER_ID
>>>     left outer join MEMBER_STATUS dfrelation_4_1
>>>       on dfrelation_4.LOGIN_MEMBER_STATUS_CODE =
>>> dfrelation_4_1.MEMBER_STATUS_CODE
>>>      and dfrelation_4_1.DISPLAY_ORDER = 2
>>>
>>> イメージとしては、dfpropで
>>> $$over($$foreignAlias$$.overRelationAlias)$$
>>> と指定したら
>>>
>>> $$localAlias$$
>>> left outer join
>>> $$foreignAlias$$
>>>   on $$localAlias$$.ID = $$foreignAlias$$.ID
>>> left outer join
>>> $$overRelationAlias$$
>>>   on $$foreignAlias$$.overRelationAlias_ID = $$overRelationAlias$$.ID
>>> and [fixedCondition]
>>>
>>> です。
>>>
>>> $$over($$localAlias$$.overRelationAlias)$$
>>> なら
>>>
>>> $$localAlias$$
>>> left outer join
>>> $$foreignAlias$$
>>>   on $$localAlias$$.ID = $$foreignAlias$$.ID
>>> left outer join
>>> $$overRelationAlias$$
>>>   on $$localAlias$$.overRelationAlias_ID = $$overRelationAlias$$.ID
>>> and [fixedCondition]
>>>
>>> で、
>>> $$over(dflocal.overRelationAlias)$$
>>> なら
>>>
>>> from dflocal
>>> left outer join
>>> $$localAlias$$
>>>   on dflocal.localAlias_ID = $$localAlias$$.ID
>>> left outer join
>>> $$foreignAlias$$
>>>   on $$localAlias$$.ID = $$foreignAlias$$.ID
>>> left outer join
>>> $$overRelationAlias$$
>>>   on dflocal.overRelationAlias_ID = $$overRelationAlias$$.ID
>>> and [fixedCondition]
>>>
>>> で、いけるのかなと。
>>>
>>> ※  [fixedCondition]は
>>>     $$overRelationAlias$$.XxxColumn = $cls(XxxType.XxxCode)
>>> とか
>>>     $$foreignAlias$$.XxxColumn = $$overRelationAlias$$.XxxColumn
>>> とか
>>>     $$localAlias$$.XxxColumn<= $$overRelationAlias$$.XxxColumn
>>> とか
>>>     dflocal.XxxColumn>= $$overRelationAlias$$.XxxColumn
>>> です。
>>>
>>> 長々とすみません。宜しくお願いします。
>>>
>>>
>>> (2010/10/11 22:37), kubo wrote:
>>>> 久保(jflute)です。
>>>>
>>>> fpさん、もうちょっとアドバイス頂ければと思います。
>>>> 定義した業務的one-to-oneの foreignTable を経由した
>>>> さらなる foreignTable のカラムを fixedCondition に
>>>> 利用するパターンですが、二つの left outer join が、
>>>> 互いに参照し合うのでSQL的に動作するのかどうか、
>>>> ちょっと疑問に思っています。
>>>>
>>>> local = MEMBER
>>>> foreign = MEMBER_LOGIN (業務的one-to-one)
>>>> foreignのforeign = MEMBER_STATUS (LOGIN経由)
>>>>
>>>> select ...
>>>>     from member dflocal
>>>>       left outer join MEMBER_STATUS dfrelation_4_1
>>>>         on dfrelation_4.LOGIN_MEMBER_STATUS_CODE =
>>>> dfrelation_4_1.MEMBER_STATUS_CODE
>>>>       left outer join MEMBER_LOGIN dfrelation_4
>>>>         on dflocal.MEMBER_ID = dfrelation_4.MEMBER_ID
>>>>        and dfrelation_4_1.DISPLAY_ORDER = 2
>>>>
>>>> だと、MEMBER_STATUS の left outer join が先に来て、
>>>> dfrelation_4 が(まだ)解決できません。順番を逆にしても:
>>>>
>>>> select ...
>>>>     from member dflocal
>>>>       left outer join MEMBER_LOGIN dfrelation_4
>>>>         on dflocal.MEMBER_ID = dfrelation_4.MEMBER_ID
>>>>        and dfrelation_4_1.DISPLAY_ORDER = 2
>>>>       left outer join MEMBER_STATUS dfrelation_4_1
>>>>         on dfrelation_4.LOGIN_MEMBER_STATUS_CODE =
>>>> dfrelation_4_1.MEMBER_STATUS_CODE
>>>>
>>>> 今度は、MEMBER_LOGIN の on 句で、
>>>> dfrelation_4_1 が解決できません。
>>>> MySQLとPostgreSQLで実際に試してエラーになりました。
>>>>
>>>> 頭の中でいけるかなぁと勝手に思っていはいたのですが、
>>>> いざやってみると確かに...。
>>>> ちょっと自分が勘違いしているかもしれません。
>>>> fpさんのところで実業務で想定しているパターンを
>>>> もう少し情報頂けないでしょうか?
>>>> (どういうSQLを想定されていますでしょうか!?)
>>>>
>>>> #
>>>> # 以下のようにすれば、いけそうですが、
>>>> # 同名カラムをどう解決したものかってとこですね...
>>>> #
>>>>
>>>> select *
>>>>     from member dflocal
>>>>       left outer join
>>>>         (select *
>>>>            from MEMBER_LOGIN
>>>>            left outer join MEMBER_STATUS dfrelation_4_1
>>>>              on MEMBER_LOGIN.LOGIN_MEMBER_STATUS_CODE =
>>>> dfrelation_4_1.MEMBER_STATUS_CODE
>>>>         ) dfrelation_4
>>>>         on dflocal.MEMBER_ID = dfrelation_4.MEMBER_ID
>>>>        and dfrelation_4.DISPLAY_ORDER = 2
>>>>
>>>>
>>>> 2010/10/11 fp<[E-MAIL ADDRESS DELETED]>:
>>>>> fpです。
>>>>>
>>>>> ありがとうございます。
>>>>>
>>>>> 申し訳ありませんが、宜しくお願いします。
>>>>>
>>>>> (2010/10/11 18:46), kubo wrote:
>>>>>> 久保(jflute)です。
>>>>>>
>>>>>>> 当方のプロジェクトでは、話に出た全パターン当てはまります。
>>>>>> なるほどー、じゃあ頑張りますよぅ。
>>>>>> こっちも「すぐに使ってもらえないかもしれない機能」を
>>>>>> 実装するのはリスクがあって、すぐに確認・実践してもらえる
>>>>>> ことで、要件に合った仕様と品質を担保してから公開できるので。
>>>>>> (なので、大分安定を重視する時期に来たDBFluteでは要件のない
>>>>>> 機能はあえて実装せずに将来の機会を待つこともあります、
>>>>>> 今回のパターンはそのつもりでした...)
>>>>>> もちろん、実現コストに全て委ねられますが、あともうちょい頑張れば
>>>>>> できそうなので。(フィルタ処理はコールバックで遅延させます)
>>>>>>
>>>>>> 2010/10/11 fp<[E-MAIL ADDRESS DELETED]>:
>>>>>>> fpです。
>>>>>>>
>>>>>>> 久保さん、ありがとうございます。
>>>>>>>
>>>>>>> 当方のプロジェクトでは、話に出た全パターン当てはまります。
>>>>>>>
>>>>>>> ただ、無理なようでしたら機能制限の範囲内で回避策を
>>>>>>> 考えますので、それほど緊急とはお考えにならないで下さい。
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> すれちがってしまいましたね。>[seasar-dotnet:1861]
>>>>>>>
>>>>>>>
>>>>>>> (2010/10/11 18:26), kubo wrote:
>>>>>>>> 久保(jflute)です。
>>>>>>>>
>>>>>>>> ああ、なるほど、業務的one-to-oneのリレーションを
>>>>>>>> 通過した先の foreignTable のことですね。
>>>>>>>> しかも、今の仕様だと辿るリレーションの中で、
>>>>>>>> 業務的one-to-oneを含めることができないので、
>>>>>>>> 参照元テーブルから辿ることもできないですね。
>>>>>>>>
>>>>>>>> 業務的one-to-oneの参照先テーブルだけは特別に、
>>>>>>>> ポイントとして指定できる唯一の foreignTable、
>>>>>>>> もしくは、リレーションで特別に辿れる業務的one-to-one
>>>>>>>> というように扱えればってところですね。
>>>>>>>>
>>>>>>>> $$over(MEMBER_LOGIN.memberStatus)$$
>>>>>>>>
>>>>>>>>       もしくは
>>>>>>>>
>>>>>>>> $$over(MEMBER.memberLoginAsValid.memberStatus)$$
>>>>>>>>
>>>>>>>> 該当の業務的one-to-oneが確定していない時点で、その奥の
>>>>>>>> リレーションを有効にしてエリアス名を取得できるかどうか、
>>>>>>>> その辺が実現の鍵になるので、ちょっと考えますね。
>>>>>>>> (場合に寄っては、置換処理をコールバックで遅延させて
>>>>>>>> 実行させるなどの工夫が必要かも...)
>>>>>>>>
>>>>>>>> ちなみに、fp さんの業務の中で、このパターンに
>>>>>>>> 当てはまるものがありますでしょうか?
>>>>>>>>
>>>>>>>> 2010/10/11 fp<[E-MAIL ADDRESS DELETED]>:
>>>>>>>>> fpです。
>>>>>>>>>
>>>>>>>>> 「OverRelation」を使わずに以下のようにできることは
>>>>>>>>> 認識しています。
>>>>>>>>>
>>>>>>>>> ; FK_MEMBER_MEMBER_LOGIN_AS_VALID = map:{
>>>>>>>>>         ; localTableName  = MEMBER    ; foreignTableName  = MEMBER_LOGIN
>>>>>>>>>         ; localColumnName = MEMBER_ID ; foreignColumnName = MEMBER_ID
>>>>>>>>>         ; fixedCondition =
>>>>>>>>>           exists(select 'TRUE' from MEMBER_STATUS st
>>>>>>>>>                   where $$foreignAlias$$.LOGIN_MEMBER_STATUS_CODE =
>>>>>>>>>                         st.MEMBER_STATUS_CODE
>>>>>>>>>                     and st.DISPLAY_ORDER = 2)
>>>>>>>>>         ; fixedSuffix = AsValid
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> (2010/10/11 16:44), fp wrote:
>>>>>>>>>> fpです。
>>>>>>>>>>
>>>>>>>>>> 久保さん、即座の御返事ありがとうございます。
>>>>>>>>>>
>>>>>>>>>> ん~、dbflute_exampledb にうまい例が見つからないのですが
>>>>>>>>>> 仮に、MEMBER ->          MEMBER_LOGIN ->          MEMBER_STATUS で
>>>>>>>>>> MEMBER_STATUS.DISPLAY_ORDER = 2 の条件で
>>>>>>>>>> MEMBER ->          MEMBER_LOGIN に業務的one-to-oneなFKを設定できる
>>>>>>>>>> とした場合、
>>>>>>>>>>
>>>>>>>>>> ; FK_MEMBER_MEMBER_LOGIN_AS_VALID = map:{
>>>>>>>>>>          ; localTableName  = MEMBER    ; foreignTableName  = MEMBER_LOGIN
>>>>>>>>>>          ; localColumnName = MEMBER_ID ; foreignColumnName = MEMBER_ID
>>>>>>>>>>          ; fixedCondition =
>>>>>>>>>>              $$over(MEMBER_LOGIN.memberStatus)$$.DISPLAY_ORDER = 2
>>>>>>>>>>          ; fixedSuffix = AsValid
>>>>>>>>>> }
>>>>>>>>>> と書きたい、ということです。
>>>>>>>>>> 定義上明示されている MEMBER_LOGIN をポイントテーブルと
>>>>>>>>>> することに曖昧さがあるとは思わないのですが。
>>>>>>>>>>
>>>>>>>>>> いままさに定義しようとしているリレーションのための
>>>>>>>>>> 条件の指定に、以下は適用できませんし。
>>>>>>>>>>> MEMBER.memberStatusByFooCode というように、
>>>>>>>>>>> 明示的にリレーションを書いてもらう仕様にしています。
>>>>>>>>>>
>>>>>>>>>> foreignTable についての認識に齟齬があるのでしょうか?
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> (2010/10/11 15:56), kubo wrote:
>>>>>>>>>>> 久保(jflute)です。
>>>>>>>>>>>
>>>>>>>>>>>> とはいえ、foreignTable をポイントとすることはできないでしょうか?
>>>>>>>>>>>
>>>>>>>>>>> 例えば、会員に会員ステータスへのFKカラムが二つあった場合、
>>>>>>>>>>> ポイントを会員ステータスにするとになります。
>>>>>>>>>>> なので、foreignTableに関しては、
>>>>>>>>>>> MEMBER.memberStatusByFooCode というように、
>>>>>>>>>>> 明示的にリレーションを書いてもらう仕様にしています。
>>>>>>>>>>> 親の親の親の親の親のカラムとかになると、指定が長くて
>>>>>>>>>>> 大変ですが、曖昧さの可能性も増えるので、
>>>>>>>>>>> そこの優先度を練り直したって感じです。
>>>>>>>>>>>
>>>>>>>>>>>>> ポイントテーブルは ORDER_ITEM で、リレーションは order。
>>>>>>>>>>>>>         ->             $$over(ORDER_ITEM.order)$$
>>>>>>>>>>>>
>>>>>>>>>>>> これは実際の構成ではなく、あくまで例ってことで (^^;
>>>>>>>>>>>
>>>>>>>>>>> おっと、そうでしたかぁ、失敬w
>>>>>>>>> _______________________________________________
>>>>>>>>> seasar-dotnet mailing list
>>>>>>>>> [E-MAIL ADDRESS DELETED]
>>>>>>>>> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> seasar-dotnet mailing list
>>>>>>>> [E-MAIL ADDRESS DELETED]
>>>>>>>> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> seasar-dotnet mailing list
>>>>>>> [E-MAIL ADDRESS DELETED]
>>>>>>> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>>>>>>>
>>>>>> _______________________________________________
>>>>>> seasar-dotnet mailing list
>>>>>> [E-MAIL ADDRESS DELETED]
>>>>>> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>>>>>
>>>>> _______________________________________________
>>>>> seasar-dotnet mailing list
>>>>> [E-MAIL ADDRESS DELETED]
>>>>> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>>>>>
>>>> _______________________________________________
>>>> seasar-dotnet mailing list
>>>> [E-MAIL ADDRESS DELETED]
>>>> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>>>
>>> _______________________________________________
>>> seasar-dotnet mailing list
>>> [E-MAIL ADDRESS DELETED]
>>> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>>>
>> _______________________________________________
>> seasar-dotnet mailing list
>> [E-MAIL ADDRESS DELETED]
>> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>
> _______________________________________________
> seasar-dotnet mailing list
> [E-MAIL ADDRESS DELETED]
> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>


seasar-dotnet メーリングリストの案内