如何获得缺失月份的价值

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'

以上是关于如何获得缺失月份的价值的主要内容,如果未能解决你的问题,请参考以下文章

我如何从反应模式引导中获得价值?

如何从上次交易中获得价值,但不是今天的交易

如何从faker获得独特的价值?

如何在php上获得价值127.0.0.1而不是::1

如何只有在改变之后才能获得价值

如何获得 CKEditor 5 的价值?