7.9 GROUPING SETS and ROLLUP()
(page 214)
There is yet another method that may be used to obtain the results seen in the previous two examples. The GROUPING SETS() extension to GROUP BY made its debut
with Oracle 9i. The entire GROUP BY … HAVING clause of the previous example can be replaced with GROUP BY GROUPING SETS(). However, just because you can do something doesn’t mean you should. Let’s look at example to understand just why you may not want to use GROUPING SETS(). Lines 31–33 in Listing 7-16 can be replaced by lines 31–36 in Listing 7-18.
还有其他的方法可以获得之前两个例子的结果。GROUPING SETS()函数对GROUP BY的扩展,在ORALCE 9i时初次登场
。之前例子中的整个GROUP BY...HAVING子句可以用GROUP BY GROUPING SETS()替换。然而,你可以这样做并不意味着你必须这样做。让我们看一个例子来理解为什么你可能不愿意使用GROUPING SETS()。列表7-16的行31-33可以用列表7-18的31-36行替换。
Listing 7-18. GROUPING SETS()
1 with tsales as (
2 select /*+ gather_plan_statistics */
3 s.quantity_sold
4 , s.amount_sold
5 , to_char(mod(cust_year_of_birth,10) * 10 ) || '-' ||
6 to_char((mod(cust_year_of_birth,10) * 10 ) + 10) age_range
7 , nvl(c.cust_income_level,'A: Below 30,000') cust_income_level
8 , p.prod_name
9 , p.prod_desc
10 , p.prod_category
11 , (pf.unit_cost * s.quantity_sold) total_cost
12 , s.amount_sold - (pf.unit_cost * s.quantity_sold) profit
13 from sh.sales s
14 join sh.customers c on c.cust_id = s.cust_id
15 join sh.products p on p.prod_id = s.prod_id
16 join sh.times t on t.time_id = s.time_id
17 join sh.costs pf on
18 pf.channel_id = s.channel_id
19 and pf.prod_id = s.prod_id
20 and pf.promo_id = s.promo_id
21 and pf.time_id = s.time_id
22 where (t.fiscal_year = 2001)
23 )
24 select
25 'Q' || to_char(grouping_id(cust_income_level,age_range)+1) query_tag
26 , prod_category
27 , decode(grouping(cust_income_level),1,'ALL INCOME',cust_income_level)
cust_income_level
28 , decode(grouping(age_range),1,'ALL AGE',age_range) age_range
29 , sum(profit) profit
30 from tsales
31 group by prod_category, grouping sets(
32 rollup(prod_category), -- sub total by product category
33 (cust_income_level), -- aggregate by category and income levels only
34 (age_range), -- aggregate by category and age only
35 (cust_income_level,age_range) -- aggregates by category, all age and income
36 )
37 --having group_id() < 1
38 order by prod_category, profit;
QUERY AGE
TAG PRODUCT CATEGORY INCOME LEVEL RANGE PROFIT
------ ---------------------- -------------------- -------- ---------------
...
Q2 Software/Other E: 90,000 - 109,999 ALL AGE $124,416.04
Q2 Software/Other F: 110,000 - 129,999 ALL AGE $169,482.11
Q4 Software/Other ALL INCOME ALL AGE $873,603.25
Q4 Software/Other ALL INCOME ALL AGE $873,603.25
756 rows selected.
The output shown in Listing 7-18 is similar to that seen when the SQL from Listing 7-16 is executed
with all of the output categories enabled. That is a major difference between using GROUP BY CUBE
HAVING GROUPING_ID() and GROUP BY GROUPING SETS. The former may be used to easily modify the
output simply by setting variables to the correct values, while output from the latter cannot be modified except by modifying or dynamically generating the SQL. Modifying the SQL means there will be more code to maintain and more resources consumed in the database. Dynamically generating the SQL is, well, usually just not a good idea if it can be avoided: it will consume more database resources, and it is much harder to troubleshoot when problems arise.
在列表7-18中展示的输出结果相似于列表7-16的SQL,其所有输出(开关)目录置有效(那是一段SQL plus脚本),的执行结果。这就是使用GROUP BY CUBE HAVING GROUPING_ID() 和GROUP BY GROUPING SETS的主要不同。前者可能用起来容易修改输出,只需简单的设定变量成正确值。而后者则不能修改,除非修改或者动态的生成SQL。修改SQL意味着有更多的代码维护和消耗更多的数据库资源。动态的生成SQL,同样,通常不是一个好主意如果能避免的话:它将消耗更多的数据库资源,且它较难定位问题。
As mentioned previously, the output in Listing 7-18 is similar to that in Listing 7-16, but not the
same. The last two lines of the output shown are duplicates. Sometimes the GROUPING_SETS() extension can cause duplicates to appear in the output. In this case, the duplicates are caused by the ROLLUP(PROD_CATEGORY) line. You can prove that to yourself by removing ROLLUP() from the code in Listing 7-18 and rerunning it. The duplicate lines will no longer appear. However, the totals for each
Product Category will no longer appear either. The solution is to use the GROUP_ID() function to identify those duplicate rows, and insert it into a HAVING clause.
如前面所述,列表7-18的输出相似于列表7-16,但不是一样的。输出中的最后两行是重复的。有些时候GROUPING_SETS() 扩展式会产生输出重复。在本例中,重复是由ROLLUP(PROD_CATEGORY)行导致的。你可以验证去除列表7-18代码中的ROLLUP()然后重新运行它。重复的行将不再出现。然而,每一产品目录(Product Category)的总计也不再出现。解决的办法是用GROUP_ID()函数去标识这些重复行,然后把它插入HAVING子句中去。
The HAVING clause can be seen commented out in Listing 7-18. If you uncomment it and then re-run the script, the output will appear as expected without the duplicate rows. Interestingly, if the ROLLUP(PROD_CATEGORY) line is replaced with (NULL), the HAVING clause can be removed, and the output will appear as expected.
在列表7-18中可见HAVING子句被注释掉了。如果你去掉注释,然后重新运行脚本,输出将不会再出现重复行。有趣的是,如果ROLLUP(PROD_CATEGORY)行被替换成NULL,HAVING子句也能去除,且输出想要的结果。
The ROLLUP() extension to GROUP BY can also be used by itself to create running subtotals that would otherwise require multiple queries joined by UNION ALL.
Suppose that someone from the Sales Department asked you to create a report showing totals of all purchases by customers whose last name begins with “Sul.” In addition, there need to be subtotals for each year by customer, each product category by customer, and a grand total of all sales.
This kind of task is easily handled by ROLLUP(). Listing 7-19 shows one way to write a query to satisfy that request.
GROUP BY的ROLLUP()扩展式本身可用来创建累加中的小计,否则就要使用UNION ALL连接多次查询。
设想销售部门的某人要你创建一报告展示所有姓以"Sul"开头的顾客的所有购买值的总计。另外,还要顾客每年的小计,顾客各产品种类,以及所有销售额的总计。
这种任务使用ROLLUP()就容易做到。列表7-19展示了写一个查询满足需求的方法。
Notice that the DECODE() and GROUPING() functions are again used to indicate subtotal rows. Also, the grand total is forced to appear at the end of the report by the use of GROUPING(M.CUST_NAME).
As the only time this value will be > 0 is when the total for all customers is calculated, the grand total appears at the end of the report as expected.
注意又使用了DECODE()和GROUPING()函数指出小计行。同样,使用GROUPING(M.CUST_NAME)将总计行强制放到了报告的末尾。
因为该值仅有一次会大于0,就是当所有客户的总计计算的时候,所以总计如期出现在了报告的末端。
Listing 7-19. ROLLUP() Subtotals
1 with mysales as (
2 select
3 c.cust_last_name ||',' || c.cust_first_name cust_name
4 , p.prod_category
5 , to_char(trunc(time_id,'YYYY'),'YYYY') sale_year
6 , p.prod_name
7 , s.amount_sold
8 from sh.sales s
9 join sh.products p on p.prod_id = s.prod_id
10 join sh.customers c on c.cust_id = s.cust_id
11 where c.cust_last_name like 'Sul%'
12 --where s.time_id = to_date('01/01/2001','mm/dd/yyyy')
13 )
14 select
15 decode(grouping(m.cust_name),1,'GRAND TOTAL',m.cust_name) cust_name
16 , decode(grouping(m.sale_year),1,'TOTAL BY YEAR',m.sale_year) sale_year
17 , decode(grouping(m.prod_category),1,'TOTAL BY CATEGORY',m.prod_category)
prod_category
18 , sum(m.amount_sold) amount_sold
19 from mysales m
20 group by rollup(m.cust_name, m.prod_category, m.sale_year)
21 order by grouping(m.cust_name), 1,2,3;
CUSTOMER SALE_YEAR PRODUCT CATEGORY AMT SOLD
------------------------------ ------------- ------------------------------ --------------
…
Sullivan,Rue 1998 Peripherals and Accessories $259.90
Sullivan,Rue 1998 Software/Other $19.59
Sullivan,Rue 2000 Electronics $2,213.30
Sullivan,Rue 2000 Hardware $1,359.06
Sullivan,Rue 2000 Peripherals and Accessories $1,169.94
Sullivan,Rue 2000 Photo $331.33
Sullivan,Rue 2000 Software/Other $933.87
Sullivan,Rue TOTAL BY YEAR Electronics $2,213.30
Sullivan,Rue TOTAL BY YEAR Hardware $1,359.06
Sullivan,Rue TOTAL BY YEAR Peripherals and Accessories $1,429.84
Sullivan,Rue TOTAL BY YEAR Photo $331.33
Sullivan,Rue TOTAL BY YEAR Software/Other $953.46
Sullivan,Rue TOTAL BY YEAR TOTAL BY CATEGORY $6,286.99
GRAND TOTAL TOTAL BY YEAR TOTAL BY CATEGORY $86,994.89
68 rows selected.
分享到:
相关推荐
《Pro Oracle SQL》一书的第七章第7.8节主要探讨了如何通过GROUPING_ID()函数来扩展Oracle SQL报告的功能。GROUPING_ID()在数据分析和报表生成中扮演着重要角色,尤其在处理分组数据时,能提供更详细的分组信息。本...
《Pro Oracle SQL》一书的第7章,7.6节专门讲解了如何使用GROUPING()函数来处理这个问题。GROUPING()函数是Oracle数据库提供的一种特殊函数,用于识别汇总结果中的NULL值,并且在分组操作中有着独特的应用。 NULL值...
《Pro Oracle SQL》是Oracle数据库查询的一本权威指南,其中第七章主要讲解了高级SQL查询技术。在7.7节“Extending Reports with GROUPING()”中,作者深入探讨了如何利用GROUPING函数来增强报告的功能性和灵活性。...
《Pro Oracle SQL》Chapter 7 Advanced Grouping 是一本关于Oracle SQL高级分组技术的专业书籍,其中7.5小节着重讲解了CUBE操作在实际工作中的应用。CUBE是SQL中的一种多维度分析工具,它允许我们在数据分组时生成...
Chapter 7 - Aggregation and Grouping Chapter 8 - Multi-Table Queries Chapter 9 - Data Transactions Chapter 10 - Advanced Queries and Scripting Chapter 11 - Full-Text Index Queries Chapter ...
为了获取多级或自定义的汇总,我们可以使用`GROUPING SETS`功能,它提供了更灵活的分组方式,同时避免了不必要的计算,提高了SQL查询的效率。 `GROUP BY GROUPING SETS`允许我们自定义想要的汇总级别,从而得到特定...
Chapter 7 - Aggregation and Grouping Chapter 8 - Multi-Table Queries Chapter 9 - Data Transactions Chapter 10 - Advanced Queries and Scripting Chapter 11 - Full-Text Index Queries Chapter ...
Chapter 3 - Tools for Accessing SQL Server Chapter 4 - Introducing Transact-SQL Language Chapter 5 - Data Retrieval Chapter 6 - SQL Functions Chapter 7 - Aggregation and Grouping ...
《Pro Oracle SQL》一书的第七章深入探讨了高级分组技术,特别是关于`HAVING`子句的部分。`HAVING`子句在SQL查询中扮演着至关重要的角色,它用于在聚合函数的结果集上设置条件,这与`WHERE`子句有所不同。`WHERE`...
Pro Oracle SQL unlocks the power of SQL in the Oracle Database—one of the most potent SQL implementations on the market today. To master it requires a three-pronged approach: learn the language ...
Chapter 3 - Tools for Accessing SQL Server Chapter 4 - Introducing Transact-SQL Language Chapter 5 - Data Retrieval Chapter 6 - SQL Functions Chapter 7 - Aggregation and Grouping ...
Chapter 3 - Tools for Accessing SQL Server Chapter 4 - Introducing Transact-SQL Language Chapter 5 - Data Retrieval Chapter 6 - SQL Functions Chapter 7 - Aggregation and Grouping ...
### Oracle SQL:核心参考知识点详解 #### 一、概述 《Oracle SQL:核心参考》(Oracle SQL: The Essential Reference)是一本由David C. Kreines撰写的书籍,于2000年由O'Reilly出版社出版。该书为Oracle SQL的...
GROUP BY 子句(rollup, cube, grouping sets)实例说明 GROUP BY 子句是 SQL 语言中用于分组数据的关键字,它可以根据一个或多个列对数据进行分组,并对每个分组应用聚合函数,以便计算和输出所需的结果。GROUP BY...
ROLLUP Operator 3-7 ROLLUP Operator Example 3-8 CUBE Operator 3-9 CUBE Operator: Example 3-10 GROUPING Function 3-11 GROUPING Function: Example 3-12 GROUPING SETS 3-13 GROUPING SETS: Example 3-15 ...
在数据库查询语言 SQL 中,`ROLLUP`, `CUBE`, 和 `GROUPING SETS` 是三个重要的概念,它们主要用于处理多维度数据的汇总和分组问题,使得数据分析更加灵活高效。接下来,我们将详细介绍这三个概念的原理、语法以及...
而在更复杂的场景下,为了方便地处理多级别的汇总数据,SQL提供了三种额外的语法:`ROLLUP`、`CUBE`以及`GROUPING SETS()`。这些语法可以帮助我们更加灵活地处理分组结果,并且可以有效地减少查询次数,提高效率。 ...
### Greenplum中的Grouping Sets实现 #### Greenplum简介 Greenplum是Pivotal公司的一款基于MPP(Massively Parallel Processing)架构的数据仓库产品,它能够在大规模数据集上提供快速的数据分析能力。Greenplom...
Aggregations and Grouping** - **聚合函数**: 讲解`COUNT`, `SUM`, `AVG`等聚合函数的使用技巧。 - **分组**: 介绍`GROUP BY`子句的作用,以及如何根据特定字段对结果进行分组汇总。 - **HAVING子句**: 讲解如何...