我参与了需要按日期构建直方图的项目。在我之前,在Java代码中完成了大量的SQL查询到每个矩形(日期子区域)的数据库。
我尝试了另一种方法:
select sum(CNT), trunc(DATE, 'MM') from DATA where DATE >= TO_DATE('01-01-2012','DD-MM-YYYY') and INC_DATE <= TO_DATE('31-12-2012','DD-MM-YYYY') group by trunc(DATE, 'MM') order by trunc(DATE, 'MM');
并从Java代码中收集ResultSet中的数据。但如果某个月没有数据,我会在直方图中错过矩形!
是否有可能修复SQL(或可能是PL / SQL)表达式以包含零和的结果中缺少日期?
或者如何在Java中构建更优雅的日期序列生成器以查找缺少的日期(与天/月/季/年对齐)?
答案 0 :(得分: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
答案 1 :(得分:3)
您需要先创建日期列表;通过创建calender table或使用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
然后,您可以将此外部联接到您的主查询,以确保填充空白:
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而不是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')
答案 2 :(得分:2)
我的生产代码基于当地大师的建议和@Ben技术:
-- generate sequence 1..N: SELECT level FROM dual CONNECT BY level <= 4; -- generates days: 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; with dates as ( select (to_date('01-01-2012','DD-MM-YYYY') + level - 1) as daterange from dual connect by level <= to_date('31-12-2012','DD-MM-YYYY') - to_date('01-01-2012','DD-MM-YYYY') + 1 ) select sum(tbl.cnt) as summ, trunc(dates.daterange, 'DDD') from dates left outer join DATA_TBL tbl on trunc(tbl.inc_date, 'DDD') = trunc(dates.daterange, 'DDD') group by trunc(dates.daterange, 'DDD') order by trunc(dates.daterange, 'DDD'); -- generates months: select ADD_MONTHS(to_date('01-01-2012','DD-MM-YYYY'), level - 1) from dual connect by level <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY')) + 1; with dates as ( select add_months(to_date('01-01-2012','DD-MM-YYYY'), level-1) as daterange from dual connect by level <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY')) + 1 ) select sum(tbl.cnt) as summ, trunc(dates.daterange, 'MM') from dates left outer join DATA_TBL tbl on trunc(tbl.inc_date, 'MM') = trunc(dates.daterange, 'MM') group by trunc(dates.daterange, 'MM') order by trunc(dates.daterange, 'MM'); -- generates quarters: select ADD_MONTHS(to_date('01-01-2012','DD-MM-YYYY'), (level-1)*3) from dual connect by level <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY'))/3 + 1; with dates as ( select add_months(to_date('01-01-2012','DD-MM-YYYY'), (level-1)*3) as daterange from dual connect by level <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY'))/3 + 1 ) select sum(tbl.cnt) as summ, trunc(dates.daterange, 'Q') from dates left outer join DATA_TBL tbl on trunc(tbl.inc_date, 'Q') = trunc(dates.daterange, 'Q') group by trunc(dates.daterange, 'Q') order by trunc(dates.daterange, 'Q'); -- generates years: select add_months(to_date('01-01-2007','DD-MM-YYYY'), (level-1)*12) from dual connect by level <= months_between(to_date('31-01-2012','DD-MM-YYYY'), to_date('01-01-2007','DD-MM-YYYY'))/12 + 1; with dates as ( select add_months(to_date('01-01-2007','DD-MM-YYYY'), (level-1)*12) as daterange from dual connect by level <= months_between(to_date('31-01-2012','DD-MM-YYYY'), to_date('01-01-2007','DD-MM-YYYY'))/12 + 1 ) select sum(tbl.cnt) as summ, trunc(dates.daterange, 'YYYY') from dates left outer join DATA_TBL tbl on trunc(tbl.inc_date, 'YYYY') = trunc(dates.daterange, 'YYYY') group by trunc(dates.daterange, 'YYYY') order by trunc(dates.daterange, 'YYYY');
但按级别连接是根据以下内容进行攻击: