Oracle PARTITION BY GROUPING_ID 和 SUM

Posted

技术标签:

【中文标题】Oracle PARTITION BY GROUPING_ID 和 SUM【英文标题】:Oracle PARTITION BY GROUPING_ID with SUM 【发布时间】:2016-01-03 00:34:49 【问题描述】:

我正在尝试实现一个简单的数据仓库分析查询,处理“YEAR_VALUE”、“MONTH_VALUE”和“INVOICE_COST”

SELECT YEAR_VALUE, MONTH_VALUE, SUM (INVOICE_VALUE) AS TOTAL_INVOICE,
RANK () OVER (PARTITION BY GROUPING_ID (YEAR_VALUE, MONTH_VALUE) ORDER BY SUM (INVOICE_VALUE) DESC) AS YEAR_RANK,
RANK () OVER (PARTITION BY YEAR_VALUE, GROUPING_ID (MONTH_VALUE) ORDER BY SUM (INVOICE_VALUE) DESC) AS MONTH_RANK
FROM FACT_WH
JOIN TIME_WH ON TIME_WH.TIME_ID = FACT_WH.TIME_ID
GROUP BY (YEAR_VALUE, MONTH_VALUE);

输出是: Output

“YEAR_RANK”应表示与其他年份相比的年度总发票价值,2016 年的 YEAR_RANK=1,2015 年的 YEAR_RANK=2

问题是 'YEAR_RANK' 的值是 1,2,3,4,5 它应该是 1,1,2,2,1 我在我的代码中找不到问题,它可能在第 2 行,我尝试了所有方法并且已经浪费了很多时间。

提前致谢。

【问题讨论】:

要回答这类问题,提供表结构的描述、提供一些示例输入数据以及所需的输出总是非常有用的。如果您能提供SQLFiddle,那就更好了。 我认为您的 grouping_id 年份排名应该只包含 YEAR_VALUE 而不是 YEAR_VALUE 和 MONTH_VALUE 【参考方案1】:

一个好的方法,尤其是在查询很复杂和/或提供令人困惑的结果的情况下,是将整个查询划分为子查询,每个子查询解决一个特定的任务。

在您的情况下,我建议首先攻击 事实和维度表的联接,并按年份和月份分组以计算 total_invoice

你会得到这样的结果

YEAR_VALUE MONTH_VALUE TOTAL_INVIOCE
---------- ----------- -------------
      2016           3         29960 
      2016           1         10700 
      2015          11          5100 
      2015           8          1680 
      2016           2           800 

请注意,您不需要任何 GROUP BY 扩展,例如 GROUPING_ID,您将使用分析函数解决所有问题

在下一步中(使用先前的结果作为因子子查询)您计算年份和月份的总数 - 使用 SUM 的分析版本。

在最后一步中,您计算​​ RANK。请注意,您需要的年份 一个 DENSE_RANK,否则你会被“跳过”排名,例如 1,3(由于一年的重复记录)。

year_rank 根本没有分区,month_rank 在 YEAR 分区,因为您订购了一年中的月份。

with data as (
-- perform join and group by in this subquery
select 2016 year_value, 3 month_value, 29960 total_invioce from dual union all
select 2016 year_value, 1 month_value, 10700 total_invioce from dual union all
select 2015 year_value, 11 month_value, 5100 total_invioce from dual union all
select 2015 year_value, 8 month_value, 1680 total_invioce from dual union all
select 2016 year_value, 2 month_value, 800 total_invioce from dual),
year_month as (
-- perform year and month summary here
select 
  year_value, month_value, total_invioce,
  sum(total_invioce) over (partition by year_value) total_invoice_year,
  sum(total_invioce) over (partition by month_value) total_invoice_month
from data
)  
-- perform ranking here
select year_value, month_value, total_invioce,
dense_rank() OVER (ORDER BY total_invoice_year DESC) year_rank,
rank() OVER (partition by year_value ORDER BY total_invoice_month DESC)  month_rank
from year_month
order by total_invioce desc;

YEAR_VALUE MONTH_VALUE TOTAL_INVIOCE  YEAR_RANK MONTH_RANK
---------- ----------- ------------- ---------- ----------
      2016           3         29960          1          1 
      2016           1         10700          1          2 
      2015          11          5100          2          1 
      2015           8          1680          2          2 
      2016           2           800          1          3

【讨论】:

以上是关于Oracle PARTITION BY GROUPING_ID 和 SUM的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 GROUP BY 或 PARTITION BY 的情况下对 Oracle SQL 中的数据进行分组

SQL Server: Difference between PARTITION BY and GROUP BY

使用 OVER (PARTITION BY ) 而不是 Group By

over partition by与group by 的区别

SQL 查询 - GROUP BY , PARTITION BY

sqlserver中分区函数 partition by与 group by 区别 删除关键字段重复列