【问题标题】:Product in a GROUP BY with potential zeroesGROUP BY 中可能为零的产品
【发布时间】:2018-10-24 11:48:16
【问题描述】:

所以我searched a bit and found 表示您可以使用 GROUP BY 和一个漂亮的数学公式在 Oracle 中对行进行乘积:exp(sum(ln(some_col)))。这非常棒,但不幸的是当some_col 可能为零时不起作用(因为ln(0) 不可能,因为 ln(x) 在接近零时是负无穷大)。

查询示例:

select
  a, b, c
  sum(d) d,
  sum(e) e,
  exp(sum(ln(f))) f
from x
group by a, b, c;

显然,由于这是值的乘积,如果其中一个为零,则乘积将为零。直接的想法是使用case,但这将要求case 语句位于聚合值或GROUP BY 中的某个值上……但事实并非如此。我不能只排除这些行,因为我仍然需要 sum(d)sum(e)

在处理潜在零点时,有什么好的方法可以做到这一点吗?我正在考虑一些涉及over(partition by ...) 的事情,但实际上,我的查询按 12 列分组,并且还有 20 个其他列正在聚合。该查询可能会变得很难看,但如果这是唯一的解决方案,我想我别无选择。

附带问题:Oracle 中没有产品功能有什么特别的原因吗?似乎包含 sum 这样的基本内容是这样的。

注意:这是 Oracle 12c。

例子:

如果我有这样的输入表(与上面的查询匹配):

| a   | b   | c   | d | e | f |
+-----+-----+-----+---+---+---+
| foo | bar | hoo | 1 | 2 | 2 |
| foo | bar | hoo | 3 | 4 | 3 |
| foo | bar | hoo | 2 | 5 | 0 |
| foo | bar | mee | 1 | 2 | 2 |
| foo | bar | mee | 3 | 4 | 3 |

我希望这样的输出:

|  a  |  b  |  c  | d | e  | f |
+-----+-----+-----+---+----+---+
| foo | bar | hoo | 6 | 11 | 0 |
| foo | bar | mee | 4 | 6  | 6 |

但是,因为第三行的 f 是 0,所以我们自然会得到 ORA-01428: argument '0' is out of rangeln(0)

【问题讨论】:

  • 向我们展示数据库架构、示例数据、当前和预期输出。请阅读How-to-Ask 这里是START 了解如何提高问题质量并获得更好答案的好地方。 How to create a Minimal, Complete, and Verifiable example
  • 添加了一个清晰的例子。
  • exp(sum(case when f != 0 then ln(f) end)) 有效吗?
  • @GaryMyers 不幸的是,这导致NULL 这不是我们想要的。也就是说,在那之后我可以在它周围扔一个nvl,所以它可能会起作用。所以,总共:nvl(exp(sum(case when f != 0 then ln(f) end)), 0)

标签: sql oracle


【解决方案1】:

首先,log(0) 不是未定义的 - 它是负无穷大。

第二:在 Oracle 中,您可以生成负无穷大,但您必须使用 BINARY_FLOAT。

select a, b, c,
       sum(d) d,
       sum(e) e,
       exp(sum(CASE WHEN f <> 0 THEN ln(f) ELSE -1/0F END)) f
  from x
  group by a, b, c;

使用您生成的数据:

A   B   C   D   E   F
foo bar hoo 6   11  0
foo bar mee 4   6   6.0000001304324524E+000

请注意,引入对数和幂函数会引入一些舍入问题,但这至少可以帮助您入门。

dbfiddle here

到负无穷...以及超越!!!!!!

:-)

【讨论】:

  • 有趣。拥抱负无穷。我在想我也可以添加一个很小的 ​​epsilon 并对结果进行四舍五入(例如round(exp(sum(ln(f + 0.000001))), 4)),但我们也可以使用负无穷大。
  • BINARY_FLOAT(或BINARY_DOUBLE)不仅需要获得无穷大语义,当与EXP() 或@ 一起使用时,它也比NUMBER大大 987654331@, as I've shown here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-24
  • 2021-09-21
  • 1970-01-01
  • 1970-01-01
  • 2013-12-05
  • 1970-01-01
相关资源
最近更新 更多