[Seasar-user:8886] Re: [DBFlute] 動的にSQLを生成する方法

kubo [E-MAIL ADDRESS DELETED]
2007年 7月 2日 (月) 18:49:24 JST


久保です。

久保です。

丸岡さんへ

> DBFluteを利用しています。
> 現在、プログラムロジックでSQLを自動生成する要件があります。
> 
> 例:名称を「あ」,「い」で曖昧検索を行ないたい場合、下記のように
> UNIONでSQLを連結したいのです。
> この検索条件の個数は不定であるため、UNIONの個数も不定です。


ある列の値に「あ」が含まれている(or で始まっている)

    もしくは

そのある列の値に「い」が含まれている(or で始まっている)


というように、
A. LikeのOR条件をしたいということでしょうか?
B. かつ、そのOR条件が不定数である
C. かつ、そのOR条件はUNIONで実現されてなければならない




DBFluteで可能は範囲を説明しておきます。

Table -- BOOK(本)
Column -- BOOK_ID(本ID)
Column -- BOOK_NAME(本の名前)


【ConditionBeanによるLike検索のOR条件】
もし、「A」と「B」だけであれば、以下のように実現することができます。

ex) 本の名前に「S2Dao」もしくは「DBFlute」が含まれているレコードを検索
    (論理削除されていないものだけを対象とする)
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
    final LikeSearchOption likeSearchOption = new LikeSearchOption();
    likeSearchOption.likeContain().splitByPipeLine();// ★部分一致&区切り文字'|'
    final LikeSearchOption.LikeAsOrCallback bookNameCallback = new LikeSearchOption.DefaultLikeAsOrCallback() {
        public String getAdditionalTargetPropertyName() {
            return BookDbm.COLUMN_UNCAP_PROP_NAME_OF_BookName;
        }
    };
    likeSearchOption.addLikeAsOrCallback(bookNameCallback);
    cb.query().setBookName_LikeSearch("S2Dao|DBFlute", likeSearchOption);// ★Like検索
    cb.query().setDeleteFlg_Equal_NonDelete();
    final List<Book> bookList = bookBhv.selectList(cb);
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

出力されるSQLのイメージは以下です。(実際にはBind変数が利用されます)

 where (BOOK.BOOK_NAME like '%S2Dao%' or BOOK.BOOK_NAME like '%DBFlute%')
   and BOOK.DELETE_FLG = 0

自分も実業務で、
画面で入力された“空白区切りの文字列”「S2Dao DBFlute JDBC ...」を使って
ある列を曖昧検索するという要件があり、上記のやり方を利用してリリースしました。


【ConditionBeanによるUnionの不定数設定】
「C」も含めた場合は、「ConditionBeanによるUnion」を利用します。
例えば曖昧検索が前方一致の場合で、OR句ではなくUNION句を利用することによって、
INDEXの恩恵を得たい場合、以下のように実現することができます。

    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
    final String[] bookNames = new String[] {"S2Dao", "DBFlute"};
    final BookCB cb = new BookCB();
    final LikeSearchOption likeSearchOption = new LikeSearchOption();
    likeSearchOption.likePrefix();// ★前方一致
    for (String bookName : bookNames) {
        final BookCB unionCB = new BookCB();
        unionCB.query().setBookName_LikeSearch(bookName, likeSearchOption);// ★Like検索
        cb.query().setDeleteFlg_Equal_NonDelete();
        cb.union(unionCB.query());
    }
    cb.query().setDeleteFlg_Equal_NonDelete();
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

出力されるSQLのイメージは以下です。(実際にはBind変数が利用されます)

select ...
  from BOOK
 where like '%S2Dao%'
   and BOOK.DELETE_FLG = 0
 union
select ...
  from BOOK
 where like '%DBFlute%'
   and BOOK.DELETE_FLG = 0



外だしSQLでは、確かにこのような不定数条件付与は「埋め込み変数コメントを利用する」
しかありません。少なくとも自分が知っている限りはですが。
(S2DaoのSQLコメントにfor文のようなものは存在しないので)
そして、その場合はBind変数を利用した条件設定ができません。

自分が実業務でこの問題に直面したときは、5つくらいそういう検索が存在したのですが、
4つは上記のConditionBeanにて実現し、1つは外だしSQLで、ベタベタに「20個のBind変数」
を用意して凌ぎました(たまたま画面入力の個数に限度が設けられていたので)。


丸岡さんの実業務では、上記のConditionBeanを利用した方法では
実現は難しいでしょうか?

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
ConditionBeanは、
  「親の親までのSelect句指定(結合)」
  「子テーブルの列での条件絞込み」
など装備しており、大抵のSQLは実現可能であります。
但し、GroupByやSQL関数を利用したい場合などは利用できません。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 




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