SQL中的乘法聚合运算符

Posted

技术标签:

【中文标题】SQL中的乘法聚合运算符【英文标题】:Multiplication aggregate operator in SQL 【发布时间】:2011-07-21 22:21:10 【问题描述】:

在 SQL 中有聚合运算符,例如 AVG、SUM、COUNT。为什么它没有乘法运算符? “MUL”之类的。

我想知道,Oracle、MSSQL、mysql 是否存在它?如果没有,是否有会产生这种行为的解决方法?

【问题讨论】:

***.com/questions/5218375/… --- 棘手的基于数学的解决方案。 is there a PRODUCT function like there is a SUM function in Oracle SQL?的可能重复 @onedaywhen - 接受的答案不适用于 0 / 更简单的解决方案:***.com/questions/3653586 【参考方案1】:

你所说的 MUL 是指值的累进乘法吗?

即使有 100 行小尺寸(比如 10 秒),您的 MUL(column) 也会溢出任何数据类型!由于误用/滥用的可能性如此之高,并且使用范围非常有限,它不需要成为 SQL 标准。正如其他人所展示的那样,有许多数学方法可以解决它,就像在 SQL 中使用标准(和常用)方法进行复杂计算的方法有很多一样。

样本数据:

Column
1
2
4
8

COUNT : 4 items (1 for each non-null)
SUM   : 1 + 2 + 4 + 8 = 15
AVG   : 3.75 (SUM/COUNT)
MUL   : 1 x 2 x 4 x 8 ? ( =64 )

为了完整起见,Oracle、MSSQL、MySQL 核心实现 *

Oracle : EXP(SUM(LN(column)))   or  POWER(N,SUM(LOG(column, N)))
MSSQL  : EXP(SUM(LOG(column)))  or  POWER(N,SUM(LOG(column)/LOG(N)))
MySQL  : EXP(SUM(LOG(column)))  or  POW(N,SUM(LOG(N,column)))
注意在 SQL Server 中使用 EXP/LOG 时,注意返回类型http://msdn.microsoft.com/en-us/library/ms187592.aspx POWER 形式允许更大的数字(使用大于欧拉数的底数),如果结果变得太大而无法使用 POWER 将其返回,您可以只返回对数值并计算SQL查询


* LOG(0) 和 LOG(-ve) 未定义。下面仅显示如何在 SQL Server 中处理此问题。可以使用相同的概念找到其他 SQL 风格的等价物

create table MUL(data int)
insert MUL select 1 yourColumn union all
           select 2 union all
           select 4 union all
           select 8 union all
           select -2 union all
           select 0

select CASE WHEN MIN(abs(data)) = 0 then 0 ELSE
       EXP(SUM(Log(abs(nullif(data,0))))) -- the base mathematics
     * round(0.5-count(nullif(sign(sign(data)+0.5),1))%2,0) -- pairs up negatives
       END
from MUL

成分:

取数据的abs(),如果最小值为0,乘以其他无效的,结果为0 当数据为 0 时,NULLIF 将其转换为空值。 abs()、log() 都返回 null,导致它被 sum() 排除 如果 data 不为 0,abs 允许我们使用 LOG 方法将负数乘以 - 我们将在其他地方跟踪负数 制定最终标志 sign(data) 返回1 for >00 for 0-1 for <0。 我们再添加一个 0.5 并再次使用 sign(),因此我们现在将 0 和 1 都归类为 1,只有 -1 归类为 -1。 再次使用 NULLIF 从 COUNT() 中删除 1,因为我们只需要计算负数。 % 2 反对 count() 负数返回要么 --> 1 如果有奇数个负数 --> 如果有偶数个负数,则为 0 更多数学技巧:我们从 0.5 中取 1 或 0,这样上面就变成了 -->(0.5-1=-0.5=>四舍五入到-1)如果有奇数个负数 -->(0.5-0= 0.5=>四舍五入到1)如果有偶数个负数 我们将这个最终的 1/-1 与 SUM-PRODUCT 值相乘以获得真实结果

【讨论】:

关于零和负数处理的不同方法请参见:***.com/questions/3653586 为避免 ANSI 警告有关从聚合或 SET 运算符中消除 NULL 值的警告,您可以将 count(nullif(sign(sign(data)+0.5),1)) 替换为 COUNT(CASE WHEN SIGN(SIGN(data)+0.5)<>1 THEN 1 END)。您也可以在执行查询之前SET ANSI_WARNINGS OFF,但我更喜欢编写查询,这样一开始就不会产生警告。 有趣的是,EXP(SUM(Log(abs(nullif(data,0))))) 中的 NULLIF(data,0) 是它工作所必需的,即使 CASE 语句应该返回 0 而不评估 ELSE 部分。如果数据集中存在零值,则省略 NULLIF(data,0) 会导致域错误。 在任何领域都有大量的“使用范围”,例如随着时间的推移增长率复合的金融领域。一只股票可能有 10 年的每日收益,这将是大约 2500 个因子(不包括周末),都类似于 1.00043 和 0.99863,它们相乘得出累积的十年增长因子。标准中缺少 MULTIPLY 是一个重大缺陷。 同意@mathguy,我们在 sql 引擎中需要它来进行财务计算,尤其是统计计算(我们在内部使用 Decimal 以获得足够的精度)。当然,exp/^ 技巧也可以,但是一些 SQL 开发人员缺乏找到这种解决方法的数学背景。产品将是标准的一个很好的增强。【参考方案2】:

在 MS SQL 中使用 CTE:

CREATE TABLE Foo(Id int, Val int)
INSERT INTO Foo VALUES(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)

;WITH cte AS 
(
    SELECT Id, Val AS Multiply, row_number() over (order by Id) as rn
    FROM Foo
    WHERE Id=1
    UNION ALL
    SELECT ff.Id, cte.multiply*ff.Val as multiply, ff.rn FROM
    (SELECT f.Id, f.Val, (row_number() over (order by f.Id)) as rn
    FROM Foo f) ff
        INNER JOIN cte
        ON ff.rn -1= cte.rn
)
SELECT * FROM cte

【讨论】:

【参考方案3】:

随着数字的增加,您将很快破坏任何数据类型。

使用 LOG/EXP 很棘手,因为数字 this question 中写了一个解决这个问题的解决方案

【讨论】:

【参考方案4】:

我看到 Oracle 的答案仍然缺失,所以这里是:

SQL> with yourTable as
  2  ( select 1 yourColumn from dual union all
  3    select 2 from dual union all
  4    select 4 from dual union all
  5    select 8 from dual
  6  )
  7  select EXP(SUM(LN(yourColumn))) As ColumnProduct from yourTable
  8  /

COLUMNPRODUCT
-------------
           64

1 row selected.

问候, 抢。

【讨论】:

【参考方案5】:

使用 PostgreSQL,您可以创建自己的聚合函数,请参阅 http://www.postgresql.org/docs/8.2/interactive/sql-createaggregate.html

要在 MySQL 上创建聚合函数,您需要构建一个 .so (linux) 或 .dll (windows) 文件。此处显示了一个示例:http://www.codeproject.com/KB/database/mygroupconcat.aspx

我不确定 mssql 和 oracle,但我敢打赌他们也可以选择创建自定义聚合。

【讨论】:

【参考方案6】:

不,但你可以使用数学:)

如果yourColumn 总是大于零:

select EXP(SUM(LOG(yourColumn))) As ColumnProduct from yourTable

【讨论】:

Konerak EXP e。 msdn.microsoft.com/en-us/library/ms179857.aspx。它是自然对数的EXP-onent,与LOG配对 -1 "ORA-00909: 参数数量无效"。编辑:哎呀,我看到这不是 Oracle 独有的问题......我已经撤消了我的 -1。 这太聪明了!帮助我解决了 AWS Athena 中的类似问题 - Presto 存在一个问题,您需要使用 ln() 而不是此处列出的 LOG() @Konerak,也许这是一个愚蠢的问题,但你能解释一下这个技巧背后的数学原理吗?您的解决方案非常适合我,但我不明白如何。 当然,达雷姆。 “LOG(x)”的意思是“我应该将 e 提高到哪个幂才能得到 x?”。现在,如果您然后 EXP 该解决方案,那么您当然会再次获得 x。你问这个号码来 EXP,你用那个号码 EXP。将其与 x^a * x^b = x^(a+b) 相结合 - 这也很容易理解:x^a 的意思是“x 本身乘以一次”。现在将它乘以 x, b 次。当然,它与 x a 次和 b 次相同。所以现在,如果你对要幂的数字求和,当你再次 EXP 时,你会得到它们的时间。【参考方案7】:

不确定是 Oracle 还是 sql-server,但在 MySQL 中,您可以像往常一样使用 *

mysql> select count(id), count(id)*10 from tablename;
+-----------+--------------+
| count(id) | count(id)*10 |
+-----------+--------------+
|       961 |         9610 |
+-----------+--------------+
1 row in set (0.00 sec)

【讨论】:

以上是关于SQL中的乘法聚合运算符的主要内容,如果未能解决你的问题,请参考以下文章

Numpy中的矩阵运算+聚合操作+arg运算(2019.1.17)

在sql数据库中,我用聚合函数sum,为啥显示操作数据类型varchar对于sum运算符无效啊?

mongodb基础整理篇————聚合操作[三]

5 - SQL Server 2008 之 四则运算比较运算逻辑运算及字符连接运算

利用Python进行数据分析-Pandas(第六部分-数据聚合与分组运算)

18 12 06 sql 的 基本语句 查询 条件查询 逻辑运算符 模糊查询 范围查询 排序 聚合函数 分组 分页 连接查询 自关联 子查询