获取行产品(乘法)

时间:2013-09-11 07:56:09

标签: mysql sql

SO,

问题

我有行乘法的问题。在SQL中,有一个SUM()函数,它计算行集的某些字段的总和。我希望得到乘法,即表格

+------+
| data |
+------+
|    2 |
|   -1 |
|    3 |
+------+

结果将是2*(-1)*3 = -6。我正在使用 DOUBLE 数据类型来存储我的数据值。

我的方法

从学校数学知道log(A x B) = log(A) + log(B) - 因此可用于创建所需的表达式,如:

SELECT
  IF(COUNT(IF(SIGN(`col`)=0,1,NULL)),0,
    IF(COUNT(IF(SIGN(`col`)<0,1,NULL))%2,-1,1)
    *
    EXP(SUM(LN(ABS(`col`))))) as product
FROM `test`;

- 你会看到这种方法的弱点 - 因为在log(X)X<=0未定义 - 我需要在计算整个表达式之前计算负号。针对此示例数据和查询in this fiddle。 另一个缺点是我们需要找出列值中是否有0(因为它是一个样本,在实际情况下,我将选择产品用于某些条件的表行的子集 - 即我不能简单从我的表中删除0-s,因为结果零产品是某些行子集的有效和预期结果)

具体细节信息

现在,最后,我的问题主要部分:当我们有这样的表达时如何处理情况:X*Y*ZX < MAXFY<MAXFX*Y>MAXF和{ {1}} - 所以我们可能有数据类型溢出(这里X*Y*Z<MAXF double MySQL数据类型的限制)。样本为here。上面的查询效果很好,但我能否始终确保它能正确处理?即当某些子产品导致溢出,但整个产品没问题(没有溢出)时,可能会出现另一种溢出问题。

或者可能有其他方法可以找到行产品?此外,在表中可能有数百万条记录(MAXF主要是,但可能有100或1000等值 - 即如果我们有一个数量,如果乘以一定数量,则高到足以溢出 DOUBLE 我上面已经描述过的问题 - 可能通过-1.1<X<=1.1计算会很慢吗?

3 个答案:

答案 0 :(得分:3)

我想这会奏效......

SELECT IF(MOD(COUNT(data < 0),2)=1
        , EXP(SUM(LOG(data)))*-1
        , EXP(SUM(LOG(data))))
          x 
  FROM my_table;

答案 1 :(得分:2)

如果您经常需要这种类型的计算,我建议您将符号和对数存储在不同的列中。

符号可以存储为1(对于正面),-1(对于底片)和0(对于零)。

对数可以作为0(或任何其他值)指定为零,但不应在计算中使用。

然后计算将是:

SELECT 
    CASE WHEN EXISTS (SELECT 1 FROM test WHERE <condition> AND datasign = 0)
         THEN 0
         ELSE (SELECT 1-2*(SUM(datasign=-1)%2) FROM test WHERE <condition>)
    END AS resultsign,

    CASE WHEN EXISTS (SELECT 1 FROM test WHERE <condition> AND datasign = 0)
         THEN -1            -- undefined log for result 0
         ELSE (SELECT SUM(datalog) FROM test WHERE <condition> AND datasign <> 0)
    END AS resultlog
  ;

这样,您就没有溢出问题。您可以检查resultlog是否超出某些限制,或者只是尝试计算resultdata = resultsign * EXP(resultlog)并查看是否出现错误。

答案 2 :(得分:1)

这个问题在低质量的海洋中是一个了不起的问题。谢谢你,即使阅读它也很愉快。

<强>精密

exp(log(a)+log(b))这个想法本身就是一个好主意。但是,在阅读"What Every Computer Scientist Should Know About Floating-Point Arithmetic"后,请确保使用DECIMAL or NUMERIC数据类型以确保您使用Precision Math,否则您的值将会出乎意料地不准确。对于几百万行,错误可以非常快地加起来! DECIMAL(根据MySQL文档)最多具有65位精度,而例如64位IEEE754浮点值最多只能有16位数(log10(2 ^ 52)= 15.65)精度!

<强>溢出

根据relevant part of the MySQL doc

  
      
  • 整数溢出导致无声环绕。
  •   
  • DECIMAL 溢出会导致截断结果和警告。
  •   
  • 浮点溢出会产生NULL结果。某些操作的溢出可能导致+ INF,-INF或NaN。
  •   

因此,如果发生浮点溢出,您可以检测到浮点溢出。

遗憾的是,如果一系列操作会产生正确的值,适合所使用的数据类型,但计算过程中至少有一个子结果不适合,那么最后你将得不到正确的值。

<强>性能

过早优化是万恶之源。尝试一下,如果速度很慢,请采取适当的措施。这样做可能不会很快,但仍然可能比获取所有结果更快,并且在应用程序服务器上执行此操作。只有测量可以决定哪个更快......