2

我参与了需要按日期构建直方图的项目。在我之前,这是通过对每个矩形(日期子区域)的大量 SQL 查询在 Java 代码中完成的。

我尝试另一种方法:

从 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')
  按 trunc 分组(日期,'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')

您不再需要 WHERE 子句,因为这是在 JOIN 中处理的。请注意,我没有使用主表中的 DATE 列,而是使用生成的日期列。如果您想将日期修改为不是月底,这将起作用,但如果您希望按月进行,您可以在 WITH 子句中截断日期。不过,在执行此操作之前,您应该了解索引。如果您的表是在 DATE 而不是在 DATE 上建立索引,TRUNC(DATE, 'MM')那么最好只在 DATE 上加入。

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 level FROM dual CONNECT BY level <= 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') + level - 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
        在 trunc(tbl.inc_date, 'DDD') = trunc(dates.daterange, 'DDD')
      按 trunc(dates.daterange, 'DDD') 分组
      按 trunc(dates.daterange, 'DDD') 排序;

-- 生成月份:
选择 ADD_MONTHS(to_date('01-01-2012','DD-MM-YYYY'), 级别 - 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
        在 trunc(tbl.inc_date, 'MM') = trunc(dates.daterange, 'MM')
      按 trunc(dates.daterange, 'MM') 分组
      按 trunc(dates.daterange, 'MM') 排序;

-- 生成宿舍:
选择 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;

日期为 (
  选择 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
        在 trunc(tbl.inc_date, 'Q') = trunc(dates.daterange, 'Q')
      按 trunc(dates.daterange, 'Q') 分组
      按 trunc(dates.daterange, 'Q') 排序;

-- 生成年份:
选择 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;

日期为 (
  选择 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
        在 trunc(tbl.inc_date, 'YYYY') = trunc(dates.daterange, 'YYYY')
      按 trunc(dates.daterange, 'YYYY') 分组
      按 trunc(dates.daterange, 'YYYY') 排序;

但是按级别连接是 hack 根据:

于 2013-01-09T17:23:52.530 回答