如何在oracle中获取与一年中所有月份相对应的记录

时间:2017-12-20 14:53:27

标签: sql oracle

我有一个数据集:

Month   id1   id2  id3    value

Jan-17   1    2    3       67
Feb-17   2    3    4       43

如何获得与一年中所有月份相对应的(id1, id2, id3)组合?

例如。输出应该如下所示: 如果我从jan-17开始:

month    id1  id2  id3   value
jan-17    1    2    3     67
feb-17    1    2    3     0
mar-17    1    2    3     0
apr-17    1    2    3     0
may-17    1    2    3     0
jun-17    1    2    3     0
jul-17    1    2    3     0
aug-17    1    2    3     0
sep-17    1    2    3     0
oct-17    1    2    3     0
nov-17    1    2    3     0
dec-17    1    2    3     0
jan-17    2    3    4     0
feb-17    2    3    4     43
mar-17    2    3    4     0
apr-17    2    3    4     0
may-17    2    3    4     0
jun-17    2    3    4     0
jul-17    2    3    4     0
aug-17    2    3    4     0
sep-17    2    3    4     0
oct-17    2    3    4     0
nov-17    2    3    4     0
dec-17    2    3    4     0

1 个答案:

答案 0 :(得分:3)

您可以使用以下内容生成一年的所有月份:

select add_months(date '2017-01-01', level - 1)
from dual
connect by level <= 12

您可以通过以下方式获取所有ID组合:

select distinct id1, id2, id3 from your_table

您可以交叉加入thos以获取所有月份的所有ID组合:

select month, id1, id2, id3
from (
  select add_months(date '2017-01-01', level - 1) as month
  from dual
  connect by level <= 12
)
cross join (
  select distinct id1, id2, id3 from your_table
)

从您的示例数据中提供24行。然后你可以再次将 连接到你的表中以获取任何值,并在没有匹配时使用coalesce来使用零:

with cte (month, id1, id2, id3) as (
  select month, id1, id2, id3
  from (
    select add_months(date '2017-01-01', level - 1) as month
    from dual
    connect by level <= 12
  )
  cross join (
    select distinct id1, id2, id3 from your_table
  )
)
select cte.month, cte.id1, cte.id2, cte.id3, coalesce(t.value, 0) as value
from cte
left join your_table t on t.month = cte.month
and t.id1 = cte.id1
and t.id2 = cte.id2
and t.id3 = cte.id3
order by cte.id1, cte.id2, cte.id3, cte.month;

MONTH             ID1        ID2        ID3      VALUE
---------- ---------- ---------- ---------- ----------
2017-01-01          1          2          3         67
2017-02-01          1          2          3          0
2017-03-01          1          2          3          0
2017-04-01          1          2          3          0
2017-05-01          1          2          3          0
2017-06-01          1          2          3          0
2017-07-01          1          2          3          0
2017-08-01          1          2          3          0
2017-09-01          1          2          3          0
2017-10-01          1          2          3          0
2017-11-01          1          2          3          0
2017-12-01          1          2          3          0
2017-01-01          2          3          4          0
2017-02-01          2          3          4         43
2017-03-01          2          3          4          0
2017-04-01          2          3          4          0
2017-05-01          2          3          4          0
2017-06-01          2          3          4          0
2017-07-01          2          3          4          0
2017-08-01          2          3          4          0
2017-09-01          2          3          4          0
2017-10-01          2          3          4          0
2017-11-01          2          3          4          0
2017-12-01          2          3          4          0

如果您的ID组合仅在其他年份出现且不想要包含这些ID,则可以通过更改ID将其限制为仅包含指定年份中任何数据的ID查询以过滤:

select distinct id1, id2, id3 from your_table
where extract(year from month) = 2017

select distinct id1, id2, id3 from your_table
where month between date '2017-01-01' and date '2017-12-01'

我假设monthDATE列,其中所有值都是一个月第一天的午夜。您可以根据需要格式化显示当然。

正如@boneist所提到的,自10g以来我们可以使用partitioned outer join而不是在单独的步骤中获取这些ID:

with months (month) as (
  select add_months(date '2017-01-01', level - 1)
  from dual
  connect by level <= 12
)
select m.month, t.id1, t.id2, t.id3, coalesce(t.value, 0) as value
from months m
left join your_table t partition by (t.id1, t.id2, t.id3)
on t.month = m.month
order by t.id1, t.id2, t.id3, m.month;

得到相同的结果:

MONTH             ID1        ID2        ID3      VALUE
---------- ---------- ---------- ---------- ----------
2017-01-01          1          2          3         67
2017-02-01          1          2          3          0
2017-03-01          1          2          3          0
...
2017-01-01          2          3          4          0
2017-02-01          2          3          4         43
2017-03-01          2          3          4          0
...

但更简单(效率更高,因为它只能击中你的桌子一次)。