[Seasar-user:16112] Re: [S2JDBC] innerJoin と leftOuterJoin で同じ Entity を指定したい

Shotaro Tsubouchi [E-MAIL ADDRESS DELETED]
2008年 10月 26日 (日) 06:27:36 JST


自己レスです。

基本的に id でしか結合されない事を考えると、
追加の結合条件の存在意義って何だろう?と思いました。

select T1_.*, T3_.*
  from FOO T1_,
       BAA T2_,
       BAA T3_,
 where T3_.FOO_ID = T1_.ID
   and T2_.FOO_ID = T1_.ID
   and T2_.ID = 1

ベタだとこう書くものを、結合をわかりやすく

select T1_.*, T3_.*
  from FOO T1_
 inner join BAA T2_ on T2_.FOO_ID = T1_.ID
 inner join BAA T3_ on T3_.FOO_ID = T1_.ID
 where T2_.ID = 1

こう書けるようにしているに過ぎないのであって、
そう考えると T2_ に対する条件なのだから、

select T1_.*, T3_.*
  from FOO T1_
 inner join BAA T2_ on T2_.FOO_ID = T1_.ID and T2_.ID = 1
 inner join BAA T3_ on T3_.FOO_ID = T1_.ID

こう書く方が自然なのではないでしょうか。
これであれば、

select() // jdbcManager.from(Foo.class)
    .innerJoin(baaList(), false)
    .innerJoin(baaList())
    .where(eq(baaList(2).id(), 1))
    .getResultList();

こんな若干トリッキーな指定をしなくても、

select() // jdbcManager.from(Foo.class)
    .innerJoin(baaList(), false, eq(baaList().id(), 1))
    .innerJoin(baaList())
    .getResultList();

で済んで、フェッチしない結合の重複を許すだけで良いですし。

なにげに、結合条件の追加の例自体、そういう使われ方だったりしてますw
http://s2container.seasar.org/2.4/ja/s2jdbc_manager_auto.html#%E7%B5%90%E5%90%88%E6%9D%A1%E4%BB%B6%E3%81%AE%E8%BF%BD%E5%8A%A0JOIN 



Shotaro Tsubouchi さんは書きました:
> ショータローこと坪内です。
> 
> いやはや、こちらこそ寝ぼけまなこであまり考えずに書いてました。。
> 
>> と JOIN ON 〜 で条件を指定するのではなく,
>> WHERE で指定すべきかと.
> 
> タイプセーフな書き方で何とか、とか考えているうちにこうなってました。
> 確かに本来は WHERE で指定するものなのでしょうが、
> スマートに書けなさそうだったので。。
> 
>> このケースで片方が leftOuterJoin なのは作為的な
>> 気がします.(^^;
> 
> このケースだと leftOuterJoin である必要は全然無かったですね。。
> 本来的に発行されるべきクエリーは、副問い合わせの必要はなく、
> 
> select T1_.*, T3_.*
>   from FOO T1_
>  inner join BAA T2_ on T2_.FOO_ID = T1_.ID
>  inner join BAA T3_ on T3_.FOO_ID = T1_.ID
>  where T2_.ID = 1
> 
> こうではないかと思います。と考えると、
> 
> ・フェッチしない結合は重複を許す
> ・WHERE で JOIN の番号を指定可能にする
> 
> ができれば良くて、
> 
> select() // jdbcManager.from(Foo.class)
>     .innerJoin(baaList(), false)
>     .innerJoin(baaList())
>     .where(eq(baaList(2).baaId(), 1))
>     .getResultList();
> 
> みたいな感じで行けるようになったりしないですかね?
> かなり希望的観測ですが。
> 
> 
> Koichi Kobayashi さんは書きました:
>> 小林 (koichik) です.
>>
>> 出かける支度中で慌て気味なので変なこと
>> 書いてるかもしれませんがご容赦ください.
>>
>> Date:    Sat, 25 Oct 2008 09:53:23 +0900
>> From:    Shotaro Tsubouchi <[E-MAIL ADDRESS DELETED]>
>> To:      [E-MAIL ADDRESS DELETED]
>> Subject: [Seasar-user:16109] [S2JDBC] innerJoin と leftOuterJoin で同じ Entity を指定したい
>>
>>> 親子関係にある Entity、Foo と Baa において、
>>> ID が 1 の Baa を持っている Foo を取得し、
>>> その Foo 毎に関連する Baa も取得したい場合、
>> ここで「ID が 1 の Baa を持っている」は
>> 結合条件ではなく選択条件なので,
>>
>>> select() // jdbcManager.from(Foo.class)
>>>     .innerJoin(baaList(), false, eq(baaList().baaId(), 1))
>>>     .leftOuterJoin(baaList())
>>>     .getResultList();
>> と JOIN ON 〜 で条件を指定するのではなく,
>> WHERE で指定すべきかと.
>>
>> となると EXISTS または IN で相関福問い合わせを
>> 使うことになりますが,S2JDBC の SimpleWhere は
>> サポートしていないので,where(String, Object...) を
>> 使うことになってしまいます.
>>
>> 相関福問い合わせは SQL だと
>>
>> 〜 where exists (select * from BAA where BAA_ID = ? and FOO_ID = T1_.FOO_ID)
>>
>> みたいになります.
>> # この例は多対多関連なので本当は FOO_ID なんて
>> # ないのかもしれませんが.
>>
>> ここで T1_ は主問い合わせの Foo のエイリアスで,
>> S2JDBC が割り振るものです.
>> S2JDBC は where(String, Object...) に渡された
>> 文字列にこのエイリアスを自動的に割り振るので
>> T1_ は省略できます.
>>
>> select() // jdbcManager.from(Foo.class)
>>     .innerJoin(baaList())
>>     .getResultList();
>>     .where("exists (select * from BAA  where BAA_ID = ? and FOO_ID = fooId", 1)
>>     .getResultList();
>>
>> のようになるかと思うのですが,試してないので
>> 怪しいかも.
>> カラム名とプロパティ名が入り乱れて気持ち悪い...
>>
>>
>>> ひとまず、AutoSelectImpl の 774 行目をコメントアウトして
>>> 例外を無視してみたところ、想定していたクエリーを発行できました。
>>> 結合条件の重複チェックが、innerJoin と leftOuterJoin で
>>> 分かれていれれば良いんですかね?
>> このケースで片方が leftOuterJoin なのは作為的な
>> 気がします.(^^;
>>
>> 制約をゆるめるなら,フェッチしない結合は重複を
>> 許すということが考えられますが,フェッチしない
>> ということは選択条件のためということになり,
>> それなら WHERE 句で頑張るのが筋かなと.
>> そのためには相関福問い合わせのサポートを向上する
>> 必要があって悩ましいですが.
>>
>>
> 


Seasar-user メーリングリストの案内