使用 oracle 获取最近 12 个月的计数及其方差

fetch last 12 months count and their variance using oracle

with sales as
(
select  COUNT(sale) As Number_of_sale, 
TO_CHAR(dates,'YYYY-MON') As Period

  from orders
    where dates between date '2020-03-01' and date '2020-03-31'
group by TO_CHAR(dates,'YYYY-MON') 

union all
select  COUNT(sale) As Number_of_sale,
TO_CHAR(dates,'YYYY-MON') As Period

  from orders
  where dates between date '2020-04-01' and date '2020-04-30'
group by TO_CHAR(dates,'YYYY-MON') 

)
select  Number_of_sale, period,
case when to_char(round((Number_of_sale-lag(Number_of_sale,1, Number_of_sale) over (order by period ))/ Number_of_sale*100,2), 'FM999999990D9999') <0 
then to_char(round(abs( Number_of_sale-lag(Number_of_sale,1, Number_of_sale) over (order by period ))/ Number_of_sale*100,2),'FM999999990D9999')||'%'||'  (Increase) '
when to_char(round((Number_of_sale-lag(Number_of_sale,1,Number_of_sale) over (order by period ))/Number_of_sale*100,2),'FM999999990D9999')>0 
then to_char(round(abs(Number_of_sale-lag(Number_of_sale,1, Number_of_sale) over (order by period ))/Number_of_sale*100,2),'FM999999990D9999')||'%'||'  (Decrease) '
END as variances
        from sales
        order by variances asc;

我得到的输出

Number_of_sale  |  Period        |Variances
   50           |   2020-Mar         |  100%(increase)
   100          |   2020-Apr         |  Null

我需要的输出:- 我需要过去 12 个月的数据以及它们与上个月的差异。

您查询的 WITH 位包含一些冗余联合,它可能会排除时间段结束的日期。考虑一下:

select  COUNT(sale) As Number_of_sale, 
TO_CHAR(dates,'YYYY-MON') As Period

  from orders
    where dates >= date '2019-03-01' and dates < date '2020-03-01'
group by TO_CHAR(dates,'YYYY-MON') 



您不需要将连续的日期范围合并在一起,只需使用更大的日期范围 - 您抱怨说您只有两个月的时间,但这就是您所要求的! (从3月1日到3月31日,结合从4月1日到30日,是两个月)

首先,您需要学习使用日期作为日期,只有在极少数情况下才需要转换为字符串(最终显示结果除外)。这不是其中的一个。你拥有的一切都可以作为日期。 有了这个,你抱怨你想要 12 个月,但你的查询只有 selects 2 个月。如果你想要最后 12 个,你必须 select 所有 12 个。你说你想要方差,但你不是在计算统计方差,而是计算月比差异(如果 1 个月与前一个月相比有多少变化)。

with parms  as (select trunc(date '&period_end_date','mon') dt from dual) 
   , sales as 
    ( select count(*) cnt 
           , trunc(dates,'mon') period
        from orders 
        cross join parms
       where trunc(dates,'mon') between add_months(dt, -12) 
                                         and last_day(dt)
       group by trunc(dates,'mon')
    ) 
select to_char(period, 'yyyy-Mon')  period
     , cnt                          number_of_sales 
     , to_char (round(abs(cnt - lag(cnt) over (order by period)) / cnt*100,2),'FM999999990D9999') ||
         case when cnt - lag(cnt) over (order by period) < 0 then ' %(Increase)'
              when cnt - lag(cnt) over (order by period) > 0 then ' %(Decrease)'
              else null
         end variances
  from sales  
order by variances asc;

工作原理 parms cte (in oracle 'subquery factoring') 基本上是因为我比较懒,不想多次输入参数值。但它也有一个优点,无论输入的实际日期是 'returns' 这个月的 1 号。 sales cte 计算前 12 个月 (add_months(dt, -12)) 和参数日期 (last_day(dt) 的最后一天的每个月的销售额。这些函数中的每一个自动调整 2 月 29 日和个别月份的不同天数。它在将日期列截断到月初后获取每个月的销售计数。
然后主查询使用简化的案例计算月与月的差异以确定增加或减少(保持不变但我认为它可能会逆转and/or你需要领先而不是滞后)。

免责声明: 因为您实际上没有提供 table 定义而不是样本数据,所以它还没有经过测试。