最終的な解決?を最下部に追記しています。ご参考まで
ご回答いただいたiwamoto_takaakiさん、masuda_yuyaさん、ありがとうございます。
DB接続をするWEBアプリケーションを作っているのですが、掲題について悩んでいるので質問させてください。
具体的には、条件検索用のフォームとその結果の件数と表が表示されているWEBページです。MyBatisを使って動的SQLを生成しています。
今まではひとつのテーブルを見ていたのですが、対象がログテーブルであるために、毎日ローテートされてしまい、検索の条件にDatePickerを使っているため、昨日などの日付で指定しまうと当然ながら取得件数が0になってしまいます。そのため、改修しようと思っています。
ログテーブル名自体は、「table_yyyyMMdd」のように普段のテーブル名の末尾に日付情報がつくだけなので、ロジックでどうにかしようと思っているのですが、実際のSQLについて考えてみると、この書き方でよいのかと疑問に思ったため、よりよい書き方があればと思い質問に至りました。自分が考え付いたのは以下です:
SQL
1SELECT * FROM 2(SELECT * FROM table)AS table UNION ALL SELECT * FROM 3(SELECT * FROM table_yyyyMMdd)AS past01 UNION ALL SELECT * FROM 4(SELECT * FROM table_yyyyMMdd)AS past02 UNION ALL SELECT * FROM 5(SELECT * FROM table_yyyyMMdd)AS past03 6# 以下略
現状、MyBatisを使って下記のように書いているのを、複数テーブルを見るように変えようと思っているというところです:
XML
1 <select id="search" resultType="package.DTOclass"> 2 SELECT * FROM table 3 <where> 4 <if test="startTime!=null and startTime!=''"> 5 AND access_time >= to_timestamp(#{start}, 'YYYY/MM/DD HH24:MI') 6 </if> 7 <if test="endTime!=null and endTime=''"> 8 AND access_time <= to_timestamp(#{end}, 'YYYY/MM/DD HH24:MI') 9 </if> 10 </where> 11 ORDER BY time DESC LIMIT 100 OFFSET #{counter} 12 </select>
上記の自分が思いついたSQLであてはめようとすると、<where>
までの間に記述を追加することになると思っています。ですが、ローテートされて残っているテーブルは10件になるため、なんだかあまりきれいじゃないような気がしています。また、速度的にもどうなのかな? と思うところがあります。
postgresqlですが、Oracleだったらこう書けるよ、とかでもよいので、何かよりよくするためのご助言を頂ければと思います。
ひとまずプログラムの中に組み込む前にベタSQLで結果を試してみたところ、当初質問を立てた意図とは変わりますが、うまくいかない部分があったので解決するまでこの質問をあけておきます(解決後質問文に顛末を追記します)。
なお、明示的に回答を求めず自己解決の心づもりでおりますが、下記に目を通してお気づきの点ございましたらご助言頂けますと幸甚です。
問題:where句が効いてない
SQL
1select*from table 2union all select*from table_20160626 3union all select*from table_20160625 4union all select*from table_20160624 5where access_time >= to_timestamp('2016/06/27 00:00','YYYY/MM/DD HH24:MI') and access_time <= to_timestamp('2016/06/27 07:00','YYYY/MM/DD HH24:MI') 6order by access_time desc limit 100 offset 1
↑6/27の0時から7時まで……の条件のつもりだが、普通に現在(17時とか)から最新順で100件になってしまう。条件を別の項目に変え(where hoge='piyo'
みたいな)ても効いておらず、普通に全データの最新100件が返される。
06/28
masuda_yuyaさんのご指摘にてSQLの文法の誤りを認識。改修して、ベタSQLとしてはこういう感じになりました:
SQL
1select*from ( 2select*from table 3union all select*from table_yyyyMMdd 4union all select*from table_yyyyMMdd 5union all select*from table_yyyyMMdd 6) tables 7where tables.access_time <= to_timestamp('2016/06/27 06:00','YYYY/MM/DD HH24:MI') 8and tables.access_time >= to_timestamp('2016/06/27 01:00','YYYY/MM/DD HH24:MI') 9order by tables.access_date desc limit 100 offset 1
WHERE句の条件は適当でよく、正常に結果が抽出できるかどうかの確認となります。問題なさそうだったので、動的SQLにするためにjavaをいじります。
- yyyyMMdd部分の生成
メインのテーブルが「table」で、本日分のデータのみが載っている。日次でローテートされ、ローテートされるとテーブル名の末尾に「_yyyyMMdd」が付与される。ここでは過去10日分のみ保持。
とりあえず、SQL組み立てでバインドのため利用している変数を宣言しているクラス内に、過去10日間のテーブル名を返すgetメソッドを作りました。
java
1 public List<String> getRotateTables(){ 2 SimpleDateFormat dateFormat=new SimpleDateFormat("yyyyMMdd"); 3 Calendar t =Calendar.getInstance(); 4 List<String> list=new ArrayList<>(); 5 String[] tmp = new String[10]; 6 for(int i=0;i<=9;i++){ 7 t.add(Calendar.DAY_OF_YEAR, -1); 8 tmp[i]="table_"+dateFormat.format(t.getTime()).toString(); 9 } 10 list.addAll(Arrays.asList(tmp)); 11 return list; 12 }
きたないっぽいですが動作すること優先で進みます。
- Mapperインタフェースに上記のパラメータ追加
- Mapper使っているDAOに上記パラメータ追加
- 検索やページングのActionクラスにも追加
最終的にSQLを組み立てているXMLを書きます。大体こういう感じです:
XML
1<select id="search" resultType="package.DTOclass"> 2 SELECT 3 * FROM 4 ( 5 SELECT * FROM table 6 <foreach item="rotate" collection="rotateList" separator=" "> 7 UNION ALL SELECT * FROM ${rotate} 8 </foreach> 9 ) tables 10 <where> 11 <if test="from!=null and from!=''"> 12 AND tables.access_time >= to_timestamp(#{from},'YYYY/MM/DD HH24:MI') 13 </if> 14 <if test="to!=null and to!=''"> 15 AND tables.access_time <= to_timestamp(#{to},'YYYY/MM/DD HH24:MI') 16 </if> 17 </where> 18 ORDER BY tables.access_time DESC LIMIT 100 OFFSET #{counter} 19 </select>
最初はまったのは、テーブル名を普通にバインド(#{rotate}
みたいに)しようとしたらException(org.postgresql.util.PSQLException: ERROR: syntax error at or near "$1"
)を出されてしまったことです。テーブル名はバインドできなさそうです。参考:mybatis/old-google-code-issues - github、iBatis奮闘記-0013 ($を使用した動的パラメータ) - いろいろ備忘録日記
検索のために複数テーブルを含めて抽出という目的が達成されたのでクローズします。

回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/06/27 09:30
2016/06/27 10:20 編集
2016/06/28 09:02