我有一位同事在寻找这个,我不记得曾经遇到过这样的事情。
是否有合理的技术可以让你模拟它?
SELECT PRODUCT(X)
FROM
(
SELECT 3 X FROM DUAL
UNION ALL
SELECT 5 X FROM DUAL
UNION ALL
SELECT 2 X FROM DUAL
)
将产生30
答案 0 :(得分:26)
select exp(sum(ln(col)))
from table;
编辑:
如果总是> 0
答案 1 :(得分:3)
DECLARE @a int
SET @a = 1
-- re-assign @a for each row in the result
-- as what @a was before * the value in the row
SELECT @a = @a * amount
FROM theTable
有一种类似字符串连接的方法:
DECLARE @b varchar(max)
SET @b = ""
SELECT @b = @b + CustomerName
FROM Customers
答案 2 :(得分:3)
这是另一种方法。这绝对是更长的方式,但它是一个有趣的项目的一部分。
你必须回到学校这一个,哈哈。他们要记住的关键是LOG是Exponent的倒数。
LOG10(X * Y)= LOG10(X)+ LOG10(Y)
或
ln(X * Y)= ln(X)+ ln(Y)(ln =自然对数,或简称Log base 10)
实施例
如果X = 5且Y = 6
X * Y = 30
ln(5)+ ln(6)= 3.4
ln(30)= 3.4
e ^ 3.4 = 30,5 x 6
也是如此EXP(3.4)= 30
如上所述,如果5和6各占一个表中的一行,我们取每个值的自然对数,总结行,然后取总和的指数得到30。
以下是SQL Server的SQL语句中的代码。可能需要进行一些编辑才能使其在Oracle上运行。希望这不是一个很大的区别,但我怀疑至少CASE声明在Oracle上是不一样的。你会注意到那里有一些额外的东西来测试行的符号是否为负数。
CREATE TABLE DUAL (VAL INT NOT NULL)
INSERT DUAL VALUES (3)
INSERT DUAL VALUES (5)
INSERT DUAL VALUES (2)
SELECT
CASE SUM(CASE WHEN SIGN(VAL) = -1 THEN 1 ELSE 0 END) % 2
WHEN 1 THEN -1
ELSE 1
END
* CASE
WHEN SUM(VAL) = 0 THEN 0
WHEN SUM(VAL) IS NOT NULL THEN EXP(SUM(LOG(ABS(CASE WHEN SIGN(VAL) <> 0 THEN VAL END))))
ELSE NULL
END
* CASE MIN(ABS(VAL)) WHEN 0 THEN 0 ELSE 1 END
AS PRODUCT
FROM DUAL
答案 3 :(得分:0)
“SQL”有许多不同的含义。当您说“sql have”时,您指的是特定的ANSI版本的SQL或供应商特定的实现。 DavidB的答案是在我测试的几个不同环境中工作的答案,但根据您的环境,您可以编写或找到与您要求的完全相同的功能。假设您使用的是Microsoft SQL Server 2005,那么可能的解决方案是在名为PRODUCT的.net代码中编写自定义聚合器,这样可以使您的原始查询完全按照您编写的方式工作。
答案 4 :(得分:0)
在c#中你可能需要这样做:
SELECT EXP(SUM(LOG([col])))
FROM table;
答案 5 :(得分:0)
accepted answer by tuinstoel是正确的,当然:
select exp(sum(ln(col)))
from table;
但是请注意,如果col
的类型为NUMBER
,当您使用BINARY_DOUBLE
时,将会发现巨大的性能改进。理想情况下,您的表中将有一个BINARY_DOUBLE
列,但是如果不可能,您仍然可以将col
强制转换为BINARY_DOUBLE
。 I got a 100x improvement in a simple test that I documented here,为此演员:
select exp(sum(ln(cast(col as binary_double))))
from table;
答案 6 :(得分:0)
是否有一种合理的技术可以让您模拟它?
一种技术可能是使用 LISTAGG
生成 product_expression 字符串并使用 XMLTABLE
+ GETXMLTYPE
来评估它:
WITH cte AS (
SELECT grp, LISTAGG(l, '*') AS product_expression
FROM t
GROUP BY grp
)
SELECT c.*, s.val AS product_value
FROM cte c
CROSS APPLY(
SELECT *
FROM XMLTABLE('/ROWSET/ROW/*'
PASSING dbms_xmlgen.getXMLType('SELECT ' || c.product_expression || ' FROM dual')
COLUMNS val NUMBER PATH '.')
) s;
输出:
+------+---------------------+---------------+
| GRP | PRODUCT_EXPRESSION | PRODUCT_VALUE |
+------+---------------------+---------------+
| b | 2*6 | 12 |
| a | 3*5*7 | 105 |
+------+---------------------+---------------+
处理组中单个 NULL 值的更健壮的版本:
WITH cte AS (
SELECT grp, LISTAGG(l, '*') AS product_expression
FROM t
GROUP BY grp
)
SELECT c.*, s.val AS product_value
FROM cte c
OUTER APPLY(
SELECT *
FROM XMLTABLE('/ROWSET/ROW/*'
passing dbms_xmlgen.getXMLType('SELECT ' || c.product_expression || ' FROM dual')
COLUMNS val NUMBER PATH '.')
WHERE c.product_expression IS NOT NULL
) s;
*
CROSS/OUTER APPLY(Oracle 12c) 是为了方便起见,可以替换为嵌套子查询。
这种方法可用于生成不同的聚合函数。