所以,
问题
我有行乘法的问题.在SQL中,有一个SUM()函数可以计算行集的某些字段的总和.我想得到乘法,即表格
+------+ | data | +------+ | 2 | | -1 | | 3 | +------+
that will be 2*(-1)*3 = -6 as a result. I'm using DOUBLE data type for storing my data values.
My approach
From school math it is known that log(A x B) = log(A) + log(B) - so that could be used to created desired expression like:
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`;
Run Code Online (Sandbox Code Playgroud)
-here you see weakness of this method - since log(X) is undefined when X<=0 - I need to count negative signs before calculating whole expression. Sample data and query for this is given in this fiddle.
Another weakness is that we need to find if there is 0 among column values (Since it is a sample, in real situation I'm going to select product for some subset of table rows with some condition(s) - i.e. I can not simply remove 0-s from my table, because result zero product is a valid and expected result for some rows subsets)
Specifics
And now, finally, my question main part: how to handle situation when we have expression like: X*Y*Z and here X < MAXF, Y<MAXF, but X*Y>MAXF and X*Y*Z<MAXF - so we have possible data type overflow (here MAXF is limit for double MySQL data type). The sample is here. Query above works well, but can I always be sure that it will handle that properly? I.e. may be there is another case with overflow issue when some sub-products causing overflow, but entire product is ok (without overflow).
或者可能有另一种方法来查找行产品?此外,在表格中可能有数百万条记录(-1.1<X<=1.1主要是,但可能有100或1000等值 - 即如果我们有上述问题,如果乘以一定数量就足以溢出DOUBLE) - 可能正在计算通过log会慢吗?
如果您经常需要这种类型的计算,我建议您将符号和对数存储在单独的列中。
符号可以存储为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
;
Run Code Online (Sandbox Code Playgroud)
这样,就不会出现溢出问题。您可以检查它resultlog是否超出了某些限制,或者只是尝试计算resultdata = resultsign * EXP(resultlog)并查看是否抛出错误。
| 归档时间: |
|
| 查看次数: |
765 次 |
| 最近记录: |