如何获得缺失月份的价值
Posted
技术标签:
【中文标题】如何获得缺失月份的价值【英文标题】:How to get value for the missing months 【发布时间】:2018-03-02 06:33:58 【问题描述】:我有一个示例表:
Month Id1 Id2 Id3 value1 value2
Dec-17 1 1 1 10 10
Jan-18 1 1 1 null null
Feb-18 1 1 1 20 10
Mar-18 1 1 1 20 10
Apr-18 1 1 1 10 30
Jan-18 2 2 2 10 20
Mar-18 2 2 2 10 10
我的表的复合键是 month+Id1+Id2+Id3 。 根据季度的月份,我想应用一些逻辑。 例如,对于季度的每个月,输出应该是前几个月的总和以及当前和未来月份的总和
我想使用滞后和领先功能,并且我在 (Id1,Id2,Id3) 上使用分区,所以我不想要 null 也不想要 Id1,Id2,Id3 中的 0。我考虑使用左外连接来获取所有月份,但这会在 Id1,Id2,Id3 中填充 null 或 0。
我想根据月份使用滞后和领先,我需要在逻辑中考虑下个月和上个月 有人可以帮忙吗
【问题讨论】:
COALESCE() 也许? COALESCE() 最终会在 ID1,Id2,Id3 中给出 null 即使最后一项添加了 0? 5 月的值无论如何都是 10,那么为什么缺少的月份是相关的?为什么你只显示五月的输出?目前尚不清楚您实际上要做什么。 嗨,Alex,修改了问题,请看一下 【参考方案1】:您似乎想要显示该月所在季度的总价值。您可以使用分析 sum()
而不是 lag()
:
sum(value) over (partition by id1, id2, id3, trunc(month, 'Q'))
演示,通过 CTE 获取样本数据,还包括本季度迄今为止的价值以供娱乐::
with your_table(Month, Id1, Id2, Id3, value) as (
select date '2017-12-01', 1, 1, 1, 10 from dual
union all select date '2018-02-01', 1, 1, 1, 10 from dual
union all select date '2018-04-01', 1, 1, 1, 10 from dual
union all select date '2018-05-01', 1, 1, 1, 10 from dual
union all select date '2018-09-01', 1, 1, 1, 20 from dual
)
select to_char(month, 'Mon-RR', 'nls_date_language=english') as month,
id1, id2, id3, value,
sum(value) over (partition by id1, id2, id3, trunc(month, 'Q')) as qtr,
sum(value) over (partition by id1, id2, id3, trunc(month, 'Q')
order by month) as qtd
from your_table;
MONTH ID1 ID2 ID3 VALUE QTR QTD
------ ---------- ---------- ---------- ---------- ---------- ----------
Dec-17 1 1 1 10 10 10
Feb-18 1 1 1 10 10 10
Apr-18 1 1 1 10 20 10
May-18 1 1 1 10 20 20
Sep-18 1 1 1 20 20 20
不存在缺少的月份,因此不影响总和。 (如果有几个月但将值设置为 null 而不是零,您会遇到问题;但是您可以合并这些)。
根据您的最新更新,您有 两个 值;您想在本季度的任何前几个月使用value1
,在本季度和本季度的任何未来月份使用value2
。
你可以得到那些有合适的窗口条款的;再次使用 CTE 为您提供新的示例数据:
with your_table(month, id1, id2, id3, value1, value2) as (
select date '2017-12-01', 1, 1, 1, 10, 10 from dual
union all select date '2018-01-01', 1, 1, 1, null, null from dual
union all select date '2018-02-01', 1, 1, 1, 10, 10 from dual
union all select date '2018-03-01', 1, 1, 1, 20, 10 from dual
union all select date '2018-04-01', 1, 1, 1, 10, 30 from dual
union all select date '2018-05-01', 1, 1, 1, 10, 10 from dual
union all select date '2018-09-01', 1, 1, 1, 20, 10 from dual
)
select to_char(month, 'Mon-RR', 'nls_date_language=english') as month,
id1, id2, id3, value1, value2,
coalesce(sum(coalesce(value1, 0)) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between unbounded preceding and 1 preceding
), 0) as qbd_value1,
coalesce(sum(coalesce(value2, 0)) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between current row and unbounded following
), 0) as qfd_value2,
coalesce(sum(coalesce(value1, 0)) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between unbounded preceding and 1 preceding
), 0)
+
coalesce(sum(coalesce(value2, 0)) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between current row and unbounded following
), 0) as qtr_value
from your_table;
得到:
MONTH ID1 ID2 ID3 VALUE1 VALUE2 QBD_VALUE1 QFD_VALUE2 QTR_VALUE
------ --- --- --- ------ ------ ---------- ---------- ----------
Dec-17 1 1 1 10 10 0 10 10
Jan-18 1 1 1 0 20 20
Feb-18 1 1 1 10 10 0 20 20
Mar-18 1 1 1 20 10 10 10 20
Apr-18 1 1 1 10 30 0 40 40
May-18 1 1 1 10 10 10 10 20
Sep-18 1 1 1 20 10 0 10 10
您不需要分别选择 value1
(qbd_value1
) 的季度前总和或 value2
(qfd_value2
) 的季度总和,我刚刚包括它们,以便您可以查看/检查它们;相关部分是将它们加在一起生成qtr_value
。
所以:
对于 Jan,它为您提供 Jan value2 (null->0) + Feb value2 (10) + Mar value2 (10) => 20。
对于 2 月,它为您提供 Jan value1 (null->0) + Feb value2 (10) + Mar value2 (10) => 20。
对于 Mar,它为您提供 Jan value1 (null->0) + Feb value1 (10) + Mar value1 (10) => 20。
不是最有用的示例数据...
对于 Apr,它为您提供 Apr value2 (30) + May value2 (10) => 40。(6 月份没有数据) 对于 5 月,它为您提供 Apr value1 (10) + May value2 (10) => 20。使用您的最新样本数据:
with your_table(month, id1, id2, id3, value1, value2) as (
select date '2017-12-01', 1, 1, 1, 10, 10 from dual
union all select date '2018-01-01', 1, 1, 1, null, null from dual
union all select date '2018-02-01', 1, 1, 1, 20, 10 from dual
union all select date '2018-03-01', 1, 1, 1, 20, 10 from dual
union all select date '2018-04-01', 1, 1, 1, 10, 30 from dual
union all select date '2018-01-01', 2, 2, 2, 10, 20 from dual
union all select date '2018-03-01', 2, 2, 2, 10, 10 from dual
)
...
同样的查询得到:
MONTH ID1 ID2 ID3 VALUE1 VALUE2 QBD_VALUE1 QFD_VALUE2 QTR_VALUE
------ --- --- --- ------ ------ ---------- ---------- ----------
Dec-17 1 1 1 10 10 0 10 10
Jan-18 1 1 1 0 20 20
Feb-18 1 1 1 20 10 0 20 20
Mar-18 1 1 1 20 10 20 10 30
Apr-18 1 1 1 10 30 0 30 30
Jan-18 2 2 2 10 20 0 30 30
Mar-18 2 2 2 10 10 10 10 20
这似乎符合您的期望。
离开您最初的问题,但查看不寻常的季度,您可以通过添加分析 min 和 max 来查看正在使用的月份(尽管如果仍然缺少月份,这些会令人困惑,所以我重新添加了 May null 值使其更清晰):
with your_table(month, id1, id2, id3, value1, value2) as (
select date '2017-12-01', 1, 1, 1, 10, 10 from dual
union all select date '2018-01-01', 1, 1, 1, null, null from dual
union all select date '2018-02-01', 1, 1, 1, 20, 10 from dual
union all select date '2018-03-01', 1, 1, 1, 20, 10 from dual
union all select date '2018-04-01', 1, 1, 1, 10, 30 from dual
union all select date '2018-05-01', 1, 1, 1, null, null from dual
union all select date '2018-01-01', 2, 2, 2, 10, 20 from dual
union all select date '2018-03-01', 2, 2, 2, 10, 10 from dual
)
select to_char(month, 'Mon-RR', 'nls_date_language=english') as month,
id1, id2, id3, value1, value2,
coalesce(sum(coalesce(value1, 0)) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between unbounded preceding and 1 preceding
), 0) as qbd_value1,
coalesce(sum(coalesce(value2, 0)) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between current row and unbounded following
), 0) as qfd_value2,
coalesce(sum(coalesce(value1, 0)) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between unbounded preceding and 1 preceding
), 0)
+
coalesce(sum(coalesce(value2, 0)) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between current row and unbounded following
), 0) as qtr_value,
to_char(min(month) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between unbounded preceding and current row
), 'Mon-RR', 'nls_date_language=english') as qtr_start,
to_char(max(month) over (
partition by id1, id2, id3, trunc(month, 'Q')
order by month
rows between current row and unbounded following
), 'Mon-RR', 'nls_date_language=english') as qtr_end
from your_table;
MONTH ID1 ID2 ID3 VALUE1 VALUE2 QBD_VALUE1 QFD_VALUE2 QTR_VALUE QTR_START QTR_END
------ --- --- --- ------ ------ ---------- ---------- ---------- --------------- ---------------
Dec-17 1 1 1 10 10 0 10 10 Dec-17 Dec-17
Jan-18 1 1 1 0 20 20 Jan-18 Mar-18
Feb-18 1 1 1 20 10 0 20 20 Jan-18 Mar-18
Mar-18 1 1 1 20 10 20 10 30 Jan-18 Mar-18
Apr-18 1 1 1 10 30 0 30 30 Apr-18 May-18
May-18 1 1 1 10 0 10 Apr-18 May-18
Jan-18 2 2 2 10 20 0 30 30 Jan-18 Mar-18
Mar-18 2 2 2 10 10 10 10 20 Jan-18 Mar-18
要获得调整后的范围,您可以在 trunc()
调用中使用 add_months()
,如 cmets 中所述,在所有分析子句中:
with your_table(month, id1, id2, id3, value1, value2) as (
select date '2017-12-01', 1, 1, 1, 10, 10 from dual
union all select date '2018-01-01', 1, 1, 1, null, null from dual
union all select date '2018-02-01', 1, 1, 1, 20, 10 from dual
union all select date '2018-03-01', 1, 1, 1, 20, 10 from dual
union all select date '2018-04-01', 1, 1, 1, 10, 30 from dual
union all select date '2018-05-01', 1, 1, 1, null, null from dual
union all select date '2018-01-01', 2, 2, 2, 10, 20 from dual
union all select date '2018-03-01', 2, 2, 2, 10, 10 from dual
)
select to_char(month, 'Mon-RR', 'nls_date_language=english') as month,
id1, id2, id3, value1, value2,
coalesce(sum(coalesce(value1, 0)) over (
partition by id1, id2, id3, trunc(add_months(month, 1), 'Q')
order by month
rows between unbounded preceding and 1 preceding
), 0) as qbd_value1,
coalesce(sum(coalesce(value2, 0)) over (
partition by id1, id2, id3, trunc(add_months(month, 1), 'Q')
order by month
rows between current row and unbounded following
), 0) as qfd_value2,
coalesce(sum(coalesce(value1, 0)) over (
partition by id1, id2, id3, trunc(add_months(month, 1), 'Q')
order by month
rows between unbounded preceding and 1 preceding
), 0)
+
coalesce(sum(coalesce(value2, 0)) over (
partition by id1, id2, id3, trunc(add_months(month, 1), 'Q')
order by month
rows between current row and unbounded following
), 0) as qtr_value,
to_char(min(month) over (
partition by id1, id2, id3, trunc(add_months(month, 1), 'Q')
order by month
rows between unbounded preceding and current row
), 'Mon-RR', 'nls_date_language=english') as qtr_start,
to_char(max(month) over (
partition by id1, id2, id3, trunc(add_months(month, 1), 'Q')
order by month
rows between current row and unbounded following
), 'Mon-RR', 'nls_date_language=english') as qtr_end
from your_table;
MONTH ID1 ID2 ID3 VALUE1 VALUE2 QBD_VALUE1 QFD_VALUE2 QTR_VALUE QTR_START QTR_END
------ --- --- --- ------ ------ ---------- ---------- ---------- --------------- ---------------
Dec-17 1 1 1 10 10 0 20 20 Dec-17 Feb-18
Jan-18 1 1 1 10 10 20 Dec-17 Feb-18
Feb-18 1 1 1 20 10 10 10 20 Dec-17 Feb-18
Mar-18 1 1 1 20 10 0 40 40 Mar-18 May-18
Apr-18 1 1 1 10 30 20 30 50 Mar-18 May-18
May-18 1 1 1 30 0 30 Mar-18 May-18
Jan-18 2 2 2 10 20 0 20 20 Jan-18 Jan-18
Mar-18 2 2 2 10 10 0 10 10 Mar-18 Mar-18
【讨论】:
嗨,Alex,我再次修改了问题,根据季度的月份,我需要添加上个月和下个月,所以我使用的是滞后和领先 @joe - 如果你能解释一下你开始做的事情会容易得多。显示所有样本数据的预期结果也很有帮助(也许没有那么多具有相同值的东西,以减少混乱)。你现在的预期结果令人困惑,我认为是矛盾的。 嗨亚历克斯!感谢您的回答。我不知道 sql 中的前面。看起来像这样,我不需要担心缺少几个月,这也是比领先,滞后更好的选择。 如何为不同的日历划分月份,例如。 trunc('May-18','Q') 返回 Apr-18 ,但是如果我的季度从六月开始呢 @joe - 最简单的方法可能是trunc(add_months(month, -1), 'Q')
。或者可能 +2,不确定你的意思,尝试两者,看看哪个适合你 *8-)【参考方案2】:
select
a.d month,nvl(id1,0) id1,nvl(id2,0) id2,nvl(id3,0) id3,nvl(value,0)value
from
( SELECT TO_CHAR(ADD_MONTHS(DATE '2018-01-01',(level-1)),'Mon-YY') d
FROM DUAL
CONNECT BY level < 13) a left join mytable
on a.d=mytable.month
如果有任何疑问 -http://sqlfiddle.com/#!4/7b8c7/14
【讨论】:
您好 ksl123,我已经编辑了我的问题,请看一下。谢谢您的回复 月份列是如何存储的? 嗨 Ksl123,我已将月份格式化为 '01-May-18'以上是关于如何获得缺失月份的价值的主要内容,如果未能解决你的问题,请参考以下文章