使用累积分析函数在查询中添加零值记录

时间:2016-06-15 11:26:46

标签: sql oracle

输入和代码:

with data as (
  select 1 id, 'A' name, 'fruit' r_group, '2007' year, '04' month, 5 sales from dual union all
  select 2 id, 'Z' name, 'fruit' r_group, '2007' year, '04' month, 99 sales from dual union all
  select 3 id, 'A' name, 'fruit' r_group, '2008' year, '05' month, 10 sales from dual union all
  select 4 id, 'B' name, 'vegetable' r_group, '2008' year,  '07'  month, 20 sales from dual
)

select year,
       month,
       r_group,
       sum(sales) sales,
       sum(opening) opening,
       sum(closing) closing
from (
  select t.*,
         (sum(sales) over (partition by name, r_group
                           order by year, month
                           rows between unbounded preceding and current row
                          ) -sales ) as opening,
         sum(sales) over (partition by name, r_group
                          order by year, month
                          rows between unbounded preceding and current row
                         ) as closing
  from data t
)
group by year, month, r_group
order by year, month

输出:

year   |   month   |  r_group   | sales   |  opening  |  closing    |
2007   |     04    |    fruit   |  104    |    0      |    104      |
2008   |     05    |    fruit   |  10     |    5      |    15       |
2008   |     07    | vegetable  |  20     |    0      |    20       | 

我希望输出如下:

year   |   month   |  r_group   | sales   |  opening  |  closing    |
2007   |     04    |    fruit   |  104    |    0      |    104      |
2008   |     05    |    fruit   |  10     |    104    |    114      |
2008   |     07    | vegetable  |  20     |    0      |    20       | 

我只能通过在month = 05和name ='Z'的数据中添加零值记录来实现所需的输出:

select 1 id, 'A' name, 'fruit' r_group, '2007', year '04' month, 5 sales from dual union all
select 2 id, 'Z' name, 'fruit' r_group, '2007', year '04' month, 99 sales from dual union all
select 3 id, 'A' name, 'fruit' r_group, '2008', year '05' month, 10 sales from dual union all
select 4 id, 'Z' name, 'fruit' r_group, '2008', year '05' month, 0 sales from dual union all
select 5 id, 'B' name, 'vegetable' r_group, '2008', year '07' month, 20 sales from dual ))

但是,我想知道我是否可以在选择查询中执行此操作,而无需编辑数据本身。

编辑

内部select语句将输入数据库表的详细版本:年,月,名,r_group,打开,关闭。换句话说,此查询的结果将用于填充db表,然后使用外部查询进行聚合:

select t.*,
         (sum(sales) over (partition by name, r_group
                           order by year, month
                           rows between unbounded preceding and current row
                          ) -sales ) as opening,
         sum(sales) over (partition by name, r_group
                          order by year, month
                          rows between unbounded preceding and current row
                         ) as closing
  from data t 

然后我将使用分析工具(第三方)聚合在r_group上而不包括名称。但是年,月,名称,r_group细节必须存在于后台。

编辑2

在其他工作中,我正在尝试动态添加缺失的数据。例如,如果在2007,04中存在name ='Z'但在2008,05中不存在那么累积函数一旦到达2008就会失败。因为,它在2008年没有名称='Z'开头它失败了。

2 个答案:

答案 0 :(得分:1)

分组R_GROUPYEARMONTH首先使用分析查询:

SELECT t.*,
       SUM( sales ) OVER ( PARTITION BY r_group ORDER BY year, month ) - sales
         AS opening,
       SUM( sales ) OVER ( PARTITION BY r_group ORDER BY year, month ) AS closing
FROM   (
  SELECT r_group,
         year,
         month,
         SUM( sales ) AS sales
  FROM   data
  GROUP BY r_group, year, month
) t
ORDER BY year, month

<强>更新

这还将包括输出中的名称:

SELECT t.*,
       SUM( sales ) OVER ( PARTITION BY r_group, dt ) AS r_group_month_sales,
       COALESCE(
         SUM( sales ) OVER (
           PARTITION BY r_group
           ORDER BY dt
           RANGE BETWEEN UNBOUNDED PRECEDING AND INTERVAL '1' MONTH PRECEDING
         ),
         0
       ) AS opening,
       SUM( sales ) OVER (
         PARTITION BY r_group
         ORDER BY dt
         RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS closing
FROM   (
  SELECT d.*,
         TO_DATE( year || month, 'YYYYMM' ) AS dt
  FROM   data d
) t
ORDER BY dt

<强>输出

ID NAME R_GROUP   YEAR MONTH SALES DT         R_GROUP_MONTH_SALES OPENING CLOSING
-- ---- --------- ---- ----- ----- ---------- ------------------- ------- -------
 1 A    fruit     2007 04        5 2007-04-01                 104       0     104
 2 Z    fruit     2007 04       99 2007-04-01                 104       0     104
 3 A    fruit     2008 05       10 2008-05-01                  10     104     114
 4 B    vegetable 2008 07       20 2008-07-01                  20       0      20

然后,您可以对此查询的输出执行任何处理。

也许是这样的:

SELECT year,
       month,
       r_group,
       MAX( r_group_month_sales ) AS sales,
       MAX( opening ) AS opening,
       MAX( closing ) AS closing,
       YOUR_THIRD_PARTY_AGGREGATION_FUNCTION( column_names ) AS other
FROM   (
  -- insert the query above
)
GROUP BY year, month, r_group
ORDER BY year, month

答案 1 :(得分:1)

您可以使用PRECEDING关键字直到前一行,而不是CURRENT ROW。

with data as (
  select 1 id, 'A' name, 'fruit' r_group, '2007' year, '04' month, 5 sales from dual union all
  select 2 id, 'Z' name, 'fruit' r_group, '2007' year, '04' month, 99 sales from dual union all
  select 3 id, 'A' name, 'fruit' r_group, '2008' year, '05' month, 10 sales from dual union all
  select 4 id, 'B' name, 'vegetable' r_group, '2008' year, '07' month, 20 sales from dual )
select t.*, 
  coalesce(sum(sales) over (partition by  r_group order by year, month rows between unbounded preceding and 1 preceding),0) opening,
  sum(sales) over (partition by  r_group order by year, month rows between unbounded preceding and current row) closing
from (
  select year, month, r_group, sum(sales) sales
  from data
  group by year, month, r_group
  ) t
order by 3,1,2;

year    month   r_group     sales   opening closing
---------------------------------------------------
2007    04      fruit       104     0       104
2008    05      fruit       10      104     114
2008    07      vegetable   20      0       20