sql - 在 Oracle SQL 中将许多列放在 group by 子句中

标签 sql oracle oracle11g group-by

在 Oracle 11g 数据库中,假设我们有表 CUSTOMERPAYMENT如下

客户

CUSTOMER_ID | CUSTOMER_NAME | CUSTOMER_AGE | CUSTOMER_CREATION_DATE
--------------------------------------------------------------------
001                     John             30              1 Jan 2017
002                     Jack             10              2 Jan 2017
003                      Jim             50              3 Jan 2017

付款

CUSTOMER_ID | PAYMENT_ID | PAYMENT_AMOUNT | 
-------------------------------------------
001                   900            100.00
001                   901            200.00
001                   902            300.00
003                   903            999.00

我们想要编写一条 SQL 来获取表 CUSTOMER 中的所有列连同每个客户的所有付款总额。有很多可能的方法可以做到这一点,但我想问以下哪一种更好。

解决方案1

SELECT C.CUSTOMER_ID
, MAX(C.CUSTOMER_NAME) CUSTOMER_NAME
, MAX(C.CUSTOMER_AGE) CUSTOMER_AGE
, MAX(C.CUSTOMER_CREATION_DATE) CUSTOMER_CREATION_DATE
, SUM(P.PAYMENT_AMOUNT) TOTAL_PAYMENT_AMOUNT
FROM CUSTOMER C
JOIN PAYMENT P ON (P.CUSTOMER_ID = C.CUSTOMER_ID)
GROUP BY C.CUSTOMER_ID;

解决方案2

SELECT C.CUSTOMER_ID
, C.CUSTOMER_NAME
, C.CUSTOMER_AGE
, C.CUSTOMER_CREATION_DATE
, SUM(P.PAYMENT_AMOUNT) PAYMENT_AMOUNT
FROM CUSTOMER C
JOIN PAYMENT P ON (P.CUSTOMER_ID = C.CUSTOMER_ID)
GROUP BY C.CUSTOMER_ID, C.CUSTOMER_NAME, C.CUSTOMER_AGE, C.CUSTOMER_CREATION_DATE

请注意,在解决方案 1 中,我使用 MAX不是因为我实际上想要最大结果,而是因为我想要列中的“一行”,我知道这些行对于具有相同 CUSTOMER_ID 的所有行都是相等的

解决方案 2 中,我避免添加误导性的 MAXSELECT部分将列放入 GROUP BY部分代替。

以我目前的知识,我更喜欢解决方案1,因为理解GROUP BY中的逻辑更重要。部分比 SELECT部分。我只会放置一组唯一键来表达查询的意图,以便应用程序可以推断出预期的行数。但不知道性能如何。

我问这个问题是因为我正在审查一个大型 SQL 的代码更改,该 SQL 将 50 列放入 GROUP BY 中子句,因为编辑者希望避免 MAX函数位于 SELECT部分。我知道我们可以以某种方式重构查询,以避免将不相关的列放在 GROUP BY 中。和SELECT部分,但请放弃该选项,因为它会影响应用程序逻辑并需要更多时间进行测试。

<小时/>

更新

按照大家的建议,我刚刚在两个版本中对我的大查询进行了测试。查询很复杂,有69行,涉及20多个表,执行计划有190多行,所以我想这里不适合展示。

我的生产数据现在很小,大约有 4000 个客户,并且查询是针对整个数据库运行的。仅表CUSTOMER还有一些引用表有TABLE ACCESS FULL在执行计划中,其他表可以通过索引访问。两个版本的执行计划在连接算法( HASH GROUP BYSORT AGGREGATE )的某些部分略有不同。

两个版本均用时约13分钟,无显着差异。

我也对类似于问题中的SQL的简化版本进行了测试。两个版本具有完全相同的执行计划和运行时间。

根据当前信息,我认为最合理的答案是,除非通过测试来确定两个版本的质量,否则这是不可预测的,因为优化器将完成这项工作。如果有人能提供任何信息来说服或拒绝这个想法,我将非常感激。

最佳答案

另一个选择是

SELECT C.CUSTOMER_ID
, C.CUSTOMER_NAME
, C.CUSTOMER_AGE
, C.CUSTOMER_CREATION_DATE
, P.PAYMENT_AMOUNT
FROM CUSTOMER C
JOIN (
 SELECT CUSTOMER_ID, SUM(PAYMENT_AMOUNT) PAYMENT_AMOUNT
 FROM PAYMENT 
 GROUP BY CUSTOMER_ID
) P ON (P.CUSTOMER_ID = C.CUSTOMER_ID)

要决定三者中哪一个更好,只需测试它们并查看执行计划即可。

关于sql - 在 Oracle SQL 中将许多列放在 group by 子句中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45693600/

相关文章:

oracle - 执行 Oracle 过程时向用户显示注释

Oracle 如何授予 CREATE ANY DIRECTORY 限制,即所有目录必须在给定目录内创建?

mysql - 这两个简单的 SQL 查询有什么区别?

sql - 使用 SELECT 的 SQL Server 变量赋值中的执行顺序

SQL Server 更新值 XML 节点

mysql - SQL如何连接两个表并提取结果

database - 如何找到记录oracle的分区

mysql - 在oracle中访问mysql数据

oracle - 更改 Apex 中帮助文本的字体大小

c# - 字符串 EndsWith 方法中 Entity Framework Linq 中的奇怪行为