我正在寻找类似于SELECT PRODUCT(table.price) FROM table GROUP BY table.sale
工作的SUM
之类的内容。
我是否遗漏了文档中的内容,或者确实没有PRODUCT
函数?
如果是这样,为什么不呢?
注意:我在postgres,mysql和mssql中查找了函数,发现没有,所以我假设所有的sql都不支持它。
答案 0 :(得分:49)
对于MSSQL,您可以使用它。它可以用于其他平台:它只是数学和对数的聚合。
SELECT
GrpID,
CASE
WHEN MinVal = 0 THEN 0
WHEN Neg % 2 = 1 THEN -1 * EXP(ABSMult)
ELSE EXP(ABSMult)
END
FROM
(
SELECT
GrpID,
--log of +ve row values
SUM(LOG(ABS(NULLIF(Value, 0)))) AS ABSMult,
--count of -ve values. Even = +ve result.
SUM(SIGN(CASE WHEN Value < 0 THEN 1 ELSE 0 END)) AS Neg,
--anything * zero = zero
MIN(ABS(Value)) AS MinVal
FROM
Mytable
GROUP BY
GrpID
) foo
答案 1 :(得分:26)
SQL Standard中没有PRODUCT
设置功能。它似乎是一个有价值的候选者(不像,例如,CONCATENATE
设置函数:它不适合SQL,例如,结果数据类型将涉及多值并且就第一范式形成问题)。
SQL标准旨在整合1990年左右的SQL产品功能,并为未来发展提供“思想领导力”。简而言之,它们记录了SQL的作用以及SQL应该做什么。没有PRODUCT
集函数表明,1990年没有供应商,但它值得包含,并且没有学术兴趣将其引入标准。
当然,供应商总是试图添加自己的功能,这些天通常作为标准的扩展而不是切线。我不记得在我使用的任何SQL产品中看到PRODUCT
设置功能(甚至需要一个功能)。
在任何情况下,使用log
和exp
标量函数(以及处理负数的逻辑)使用SUM
设置函数,可以非常简单地解决这个问题。有关示例代码,请参阅@ gbn的答案。不过,我从来不需要在商业应用程序中这样做。
总之,我最好的猜测是SQL终端用户不需要PRODUCT
设置功能;此外,任何具有学术兴趣的人都可能会找到可接受的解决方法(即不会重视PRODUCT
集函数提供的语法糖。)
出于兴趣,SQL Server Land确实需要新的集合函数,但对于窗口函数种类(以及标准SQL)也是如此。有关详细信息,包括如何参与进一步的驾驶需求,请参阅Itzik Ben-Gan's blog。
答案 2 :(得分:21)
我不知道为什么没有一个,但是(更多地关注负数)你可以使用日志和指数来做: -
select exp (sum (ln (table.price))) from table ...
答案 3 :(得分:8)
您可以执行产品聚合功能,但您必须自己进行数学计算,例如......
SELECT
Exp(Sum(IIf(Abs([Num])=0,0,Log(Abs([Num])))))*IIf(Min(Abs([Num]))=0,0,1)*(1-2*(Sum(IIf([Num]>=0,0,1)) Mod 2)) AS P
FROM
Table1
答案 4 :(得分:6)
T-SQL中有一个巧妙的技巧(不确定它是否为ANSI)允许将一组行中的字符串值连接成一个变量。看起来它也适用于倍增:
declare @Floats as table (value float)
insert into @Floats values (0.9)
insert into @Floats values (0.9)
insert into @Floats values (0.9)
declare @multiplier float = null
select
@multiplier = isnull(@multiplier, '1') * value
from @Floats
select @multiplier
这可能比log / exp解决方案在数值上更稳定。
答案 5 :(得分:3)
我认为这是因为没有编号系统能够容纳许多产品。由于数据库是针对大量记录而设计的,因此1000个数字的乘积将是超大型的,并且在浮点数的情况下,传播的误差将是巨大的。
另请注意,使用日志可能是一个危险的解决方案。虽然在数学上log(a * b)= log(a)* log(b),但它可能不在计算机中,因为我们没有处理实数。如果计算2 ^(log(a)+ log(b))而不是* b,则可能会得到意外结果。例如:
SELECT 9999999999 * 99999999974482,EXP(LOG(9999999999)+ LOG(99999999974482))
在Sql Server中返回
999999999644820000025518,9.99999999644812E + 23
所以我的观点是,当您尝试做产品时,请仔细进行测试并进行大量测试。
答案 6 :(得分:1)
解决此问题的一种方法(如果您使用的是脚本语言)是使用group_concat函数。
例如,SELECT group_concat(table.price) FROM table GROUP BY table.sale
这将返回一个字符串,其中包含相同销售价值的所有价格,以逗号分隔。 然后使用解析器,您可以获得每个价格,并进行乘法运算。 (在php中你甚至可以使用array_reduce函数,实际上在php.net manual你得到一个合适的例子)。
干杯
答案 7 :(得分:0)
可以使用现代SQL功能(例如窗口函数和CTE)解决该问题。一切都是标准SQL,并且与基于对数的解决方案不同,它不需要从整数世界切换到浮点世界,也不需要处理非正数。只需对行编号并在递归查询中评估产品,直到没有剩余行:
with recursive t(c) as (
select unnest(array[2,5,7,8])
), r(c,n) as (
select t.c, row_number() over () from t
), p(c,n) as (
select c, n from r where n = 1
union all
select r.c * p.c, r.n from p join r on p.n + 1 = r.n
)
select c from p where n = (select max(n) from p);
由于您的问题涉及按销售列分组,因此情况有些复杂,但仍然可以解决:
with recursive t(sale,price) as (
select 'multiplication', 2 union
select 'multiplication', 5 union
select 'multiplication', 7 union
select 'multiplication', 8 union
select 'trivial', 1 union
select 'trivial', 8 union
select 'negatives work', -2 union
select 'negatives work', -3 union
select 'negatives work', -5 union
select 'look ma, zero works too!', 1 union
select 'look ma, zero works too!', 0 union
select 'look ma, zero works too!', 2
), r(sale,price,n,maxn) as (
select t.sale, t.price, row_number() over (partition by sale), count(1) over (partition by sale)
from t
), p(sale,price,n,maxn) as (
select sale, price, n, maxn
from r where n = 1
union all
select p.sale, r.price * p.price, r.n, r.maxn
from p
join r on p.sale = r.sale and p.n + 1 = r.n
)
select sale, price
from p
where n = maxn
order by sale;
结果:
sale,price
"look ma, zero works too!",0
multiplication,560
negatives work,-30
trivial,8
在Postgres上测试。
答案 8 :(得分:0)
基于笛卡尔积的基数是特定集合的基数的结果的另一种方法;-)
⚠警告:此示例仅出于娱乐目的,并且颇具学术意义,请勿在生产中使用! (除了它仅用于正整数和实际上很小的整数)⚠
with recursive t(c) as (
select unnest(array[2,5,7,8])
), p(a) as (
select array_agg(c) from t
union all
select p.a[2:]
from p
cross join generate_series(1, p.a[1])
)
select count(*) from p where cardinality(a) = 0;
答案 9 :(得分:0)
一种方法是结合两个内置函数,如下所示:
SELECT table.sale, AVG(table.price) * COUNT(table.price) FROM table GROUP BY table.sale