2

日付ごとにヒストグラムを作成する必要があるプロジェクトに参加しました。私が Java コードでこれを行う前に、各長方形 (日付の部分領域) に対して DB への大量の SQL クエリを実行していました。

私は別のアプローチを試みます:

DATA から sum(CNT), trunc(DATE, 'MM') を選択
  ここで、DATE >= TO_DATE('01-01-2012','DD-MM-YYYY')
  INC_DATE <= TO_DATE('31-12-2012','DD-MM-YYYY')
  group by trunc(DATE, 'MM')
  順番 trunc(DATE, 'MM');

Java コードで ResultSet からデータを収集します。しかし、ある月にデータがない場合、ヒストグラムに四角形がありません!!!

SQL (または PL/SQL の場合もある) 式を修正して、欠落している日付をゼロサムの結果に含めることはできますか?

または、欠落している日付 (日/月/四半期/年に合わせて) を見つけるために Java でより洗練された日付シーケンス ジェネレーターを構築する方法は?

4

3 に答える 3

4

このようなことを試してください(単純化された例):

with 
months_int as
(select trunc(min(inc_date), 'MM') min_month, trunc(max(inc_date), 'MM') max_month
 from data),
months as
(
  select add_months(min_month, level-1) mnth_date
  from months_int 
  connect by add_months(min_month, level-1)<= max_month
  )
select  mnth_date, sum(cnt) 
from data  right outer join months on trunc(inc_date, 'MM') = mnth_date
group by mnth_date
order by mnth_date

ここにsqlfiddleの例があります

于 2013-01-09T09:15:31.683 に答える
3

最初に日付のリストを作成する必要があります。カレンダー テーブルを作成するか、 CONNECT BY構文を使用します。

select to_date('01-01-2012','DD-MM-YYYY') + level - 1
  from dual
connect by level <= to_date('31-12-2012','DD-MM-YYYY') 
                    - to_date('01-01-2012','DD-MM-YYYY') + 1

次に、これをメインクエリに LEFT OUTER JOIN して、ギャップが確実に入力されるようにすることができます。

with the_dates as (
  select to_date('01-01-2012','DD-MM-YYYY') + level - 1 as the_date
    from dual
 connect by level <= to_date('01-01-2012','DD-MM-YYYY') 
                      - to_date('31-12-2012','DD-MM-YYYY') + 1
         )
select sum(b.cnt), trunc(a.the_date, 'MM') 
  from the_dates a
  left outer join data b
    on a.the_date = b.date
 group by trunc(a.the_date, 'MM')
 order by trunc(a.the_date, 'MM')

これは JOIN で処理されるため、WHERE 句は不要になりました。メインテーブルの DATE 列ではなく、生成されたテーブルの日付を使用していることに注意してください。これは、日付を月末に変更したくない場合に機能しますが、月ごとに変更したい場合は、WITH 句で日付を切り捨てることができます。ただし、これを行う前にインデックスに注意する必要があります。テーブルのインデックスが DATE であり、そうでないTRUNC(DATE, 'MM')場合は、DATE のみで JOIN することをお勧めします。

DATE は予約語であるため、列の名前としては不適切です。あなたはそれを使用していないと思いますが、注意する必要があります。

カレンダー テーブルを使用している場合は、次のようになります。

select sum(b.cnt), trunc(a.the_date, 'MM') 
  from calender_table a
  left outer join data b
    on a.the_date = b.date
 where a.the_date >= to_date('01-01-2012','DD-MM-YYYY') 
   and a.the_date <= to_date('31-12-2012','DD-MM-YYYY')
 group by trunc(a.the_date, 'MM')
 order by trunc(a.the_date, 'MM')
于 2013-01-09T09:14:46.973 に答える
2

地元の第一人者のアドバイスと @Ben テクニックに基づく私の製品コード:

-- シーケンス 1..N を生成します。
SELECT レベル FROM デュアル CONNECT BY レベル <= 4;

-- 日を生成します。
to_date('01-01-2012','DD-MM-YYYY') + レベル - 1 を選択
  デュアルから
レベルで接続 <= to_date('31-12-2012','DD-MM-YYYY') - to_date('01-01-2012','DD-MM-YYYY') + 1;

日付を (
  (to_date('01-01-2012','DD-MM-YYYY') + レベル - 1) を日付範囲として選択します
    デュアルから
    レベルで接続 <= to_date('31-12-2012','DD-MM-YYYY') - to_date('01-01-2012','DD-MM-YYYY') + 1
  ) sum(tbl.cnt) を summ, trunc(dates.daterange, 'DDD') として選択
      日付から
           左外部結合 DATA_TBL tbl
        on trunc(tbl.inc_date, 'DDD') = trunc(dates.daterange, 'DDD')
      trunc(dates.daterange, 'DDD') でグループ化
      並べ替え trunc(dates.daterange, 'DDD');

-- 月を生成します。
select ADD_MONTHS(to_date('01-01-2012','DD-MM-YYYY'), level - 1)
  デュアルから
レベルで接続 <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY')) + 1;

日付を (
  日付範囲として add_months(to_date('01-01-2012','DD-MM-YYYY'), level-1) を選択します
    デュアルから
    レベルで接続 <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY')) + 1
  ) sum(tbl.cnt) を summ, trunc(dates.daterange, 'MM') として選択
      日付から
           左外部結合 DATA_TBL tbl
        on trunc(tbl.inc_date, 'MM') = trunc(dates.daterange, 'MM')
      trunc(dates.daterange, 'MM') でグループ化
      順番 trunc(dates.daterange, 'MM');

-- 四半期を生成します。
select ADD_MONTHS(to_date('01-01-2012','DD-MM-YYYY'), (レベル-1)*3)
  デュアルから
  レベルで接続 <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY'))/3 + 1;

日付を (
  日付範囲として add_months(to_date('01-01-2012','DD-MM-YYYY'), (level-1)*3) を選択します
    デュアルから
    レベルで接続 <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY'))/3 + 1
  ) sum(tbl.cnt) を summ, trunc(dates.daterange, 'Q') として選択
      日付から
           左外部結合 DATA_TBL tbl
        on trunc(tbl.inc_date, 'Q') = trunc(dates.daterange, 'Q')
      trunc(dates.daterange, 'Q') でグループ化
      並べ替え trunc(dates.daterange, 'Q');

-- 年を生成します。
select add_months(to_date('01-01-2007','DD-MM-YYYY'), (レベル-1)*12)
  デュアルから
  レベルで接続 <= months_between(to_date('31-01-2012','DD-MM-YYYY'), to_date('01-01-2007','DD-MM-YYYY'))/12 + 1;

日付を (
  日付範囲として add_months(to_date('01-01-2007','DD-MM-YYYY'), (level-1)*12) を選択します
    デュアルから
    レベルで接続 <= months_between(to_date('31-01-2012','DD-MM-YYYY'), to_date('01-01-2007','DD-MM-YYYY'))/12 + 1
  ) sum(tbl.cnt) を summ, trunc(dates.daterange, 'YYYY') として選択
      日付から
           左外部結合 DATA_TBL tbl
        on trunc(tbl.inc_date, 'YYYY') = trunc(dates.daterange, 'YYYY')
      trunc(dates.daterange, 'YYYY') でグループ化
      順番 trunc(dates.daterange, 'YYYY');

しかし、レベルごとに接続することは、次のようにハックされます。

于 2013-01-09T17:23:52.530 に答える