在 oracle 中的 case 或 decode 语句中使用 sum

Posted

技术标签:

【中文标题】在 oracle 中的 case 或 decode 语句中使用 sum【英文标题】:Using sum inside a case or decode statement in oracle 【发布时间】:2014-09-19 11:20:47 【问题描述】:

我试图寻找线索,但在任何地方都没有得到满意的答案。

我的问题是我有一个巨大的 select 语句,其中几乎一半的列来自子查询,在这些子查询中我必须检查很多东西。

我知道 oracle 在聚合函数方面是严格的,但是当我在其中一个子查询中尝试这样的事情时,我得到了预期的输出:

SELECT DECODE(NVL(SUM(Qty1),0),0,SUM(Qty2),SUM(Qty1))
FROM test_v
WHERE item_no    = 1234567;

但奇怪的是,当我将其修改为:

SELECT 
DECODE(FLAG,1,SUM(Qty2),SUM(Qty1))
FROM test_v
WHERE item_no    = 1234567;

我收到此错误:

ORA-00937: not a single-group group function
00937. 00000 -  "not a single-group group function"
*Cause:    
*Action:
Error at Line: 9 Column: 8`

为什么它在两个几乎相似的查询中给出不同的结果。我知道它可以通过使用GROUP BY 来解决,但是当我在输出中没有得到任何其他列时,我该如何决定GROUP BY 子句。

我还继续尝试使用这样的CASE 声明,但没有用:

SELECT
CASE
WHEN flag = 1 THEN
SUM(Qty2)
WHEN flag = 0 THEN
SUM(Qty1)
END Qty
FROM test_v
WHERE item_no    = 1234567;

我仍然遇到同样的错误。

我知道我可以通过使用另一个子查询来计算 SUM 来覆盖这一点,但这就像生活在一个 select 中的几代子查询一样,出于审美、性能和个人原因,我不希望过度使用子查询。

任何想法为什么第一个有效而这无效??

【问题讨论】:

【参考方案1】:

这是产生错误的查询:

SELECT DECODE(FLAG, 1, SUM(Qty2), SUM(Qty1))
FROM test_v
WHERE item_no    = 1234567;

这是一个聚合查询。没有group by,结果集中只有一组,汇总所有数据。

问题是flag 不在聚合函数中。应该使用哪个值?每行都有一个。这就是为什么 SQL(通常)要求聚合查询中的所有表达式都必须是聚合函数,group by 中提到的列除外。

以下方法可行:

SELECT DECODE(MAX(FLAG), 1, SUM(Qty2), SUM(Qty1))
FROM test_v
WHERE item_no    = 1234567;

注意:我使用 decode() 只是因为它在您的示例查询中。你应该学会使用case

【讨论】:

哇!这东西行得通! :) :) 并指出先生..将使用case 语句而不是解码!感谢您这么快分享这么棒的技巧! :) @Neels:如果您认为这是一个技巧,那么您应该真的阅读 SQL 中的聚合。 Gordon 只是向您展示了一种 方法来使语句在句法上 正确。这真的恰好是您正在寻找的查询吗?您甚至了解 Gordon 的查询是如何工作的吗? @ThorstenKettner:嗯,这里使用的聚合适用于我的情况(显然我不能展示我的整个代码来证明我理解)。了解戈登的询问中发生的事情并不是一门火箭科学。不要认为我在语法方面错了,只是错过了使用正确的聚合!而且我仍然会称其为技巧,因为在不影响结果的情况下,这会带来解决方案。 @Neels:正如 Gordon 所说,应该使用哪个记录的标志?他展示了一种方法,当至少一条记录具有标志 1 时,总和为 qty2。当没有记录具有标志 0 时,或者当超过 50% 的记录具有标志 1 时,他也可以展示一种方法。当您不关心单个值时,为什么每条记录中甚至还有一个标志(如:对于标记为 1 sum qty2 的每条记录,对于其他总和 qty1)?因为这恰好是适合您的解决方案,好吧。但是当你把它当作一个把戏时,你似乎没有理解正在发生的事情以及还有哪些其他选择。对不起。 @ThorstenKettner:好的.. 只是让你知道,我的实际查询类似于SELECT CASE WHEN max(a.flag) = 1 THEN SUM(a.qty2) WHEN max(a.flag) = 0 THEN decode(nvl(sum(a.qty1),0),0,sum(a.qty2),sum(a.qty1)) END qty FROM test_v WHERE item_no = 1234567 AND flag= i_flag 这个i_flag 被动态传递到这个查询中。这可能不是最好的解决方案,但我知道发生了什么! :)

以上是关于在 oracle 中的 case 或 decode 语句中使用 sum的主要内容,如果未能解决你的问题,请参考以下文章

Oracle Sql关于case-when,if-then,decode

decode()与case then 学习与使用

case...when...和decode——oracle

Oracle的case when 和decode

Oracle Decode()函数和CASE语句的比较

Oracle特有函数 case when decode exists 分页rownum