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 >0
、0 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运算符无效啊?
5 - SQL Server 2008 之 四则运算比较运算逻辑运算及字符连接运算
利用Python进行数据分析-Pandas(第六部分-数据聚合与分组运算)
18 12 06 sql 的 基本语句 查询 条件查询 逻辑运算符 模糊查询 范围查询 排序 聚合函数 分组 分页 连接查询 自关联 子查询