2011-03-24 64 views
22

SQL中有聚合運算符,如AVG,SUM,COUNT。爲什麼它沒有乘法運算符? 「MUL」什麼的。SQL中的多項式聚合運算符

我在想,它是否存在Oracle,MSSQL,MySQL?如果沒有,會有什麼解決方法可以解決這個問題?

+3

http://stackoverflow.com/questions/5218375/aggregate-multiplicate-function/5219216#5219216 ---棘手的基於數學的解決方案。 – zerkms 2011-03-24 07:51:08

+0

[是否有像Oracle SQL中有SUM函數那樣的PRODUCT函數?](http://stackoverflow.com/questions/403924/is-there-a-product-function-like-there-is- a-sum-function-in-oracle-sql) – onedaywhen 2011-03-24 09:25:47

+0

@onedaywhen - 接受的答案不適用於0/<0數字。另外,OP在一個問題上試圖覆蓋3個DBMS。 「確切」重複是一個伸縮 – RichardTheKiwi 2011-03-24 09:35:14

回答

35

By MUL you mean mean progressive multiplication of values?

即使有100行的一些小尺寸(比如10s),你的MUL(列)也會溢出任何數據類型!由於濫用/濫用的可能性很高,使用範圍非常有限,因此不需要成爲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) 

爲了完整起見,甲骨文,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表格允許更大的數字(使用大於歐拉數的基數),並且在結果變得太大以至於打開它使用電源時,可以僅返回對數值計算和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 

成份:

  • 取數據的絕對值(),如果min爲0,相乘通過其他任何無用的方法,結果爲0
  • 當數據爲0時,NULLIF將其轉換爲空值。如果數據不是0,abs允許我們使用LOG方法多個負數 - 我們將跟蹤消極情況,如果數據不是0,其他地方
  • 工作了最終籤
    • 號(數據)返回1 for >00 for 0-1 for <0
    • 我們再添加一個0.5並再次採用sign(),所以我們現在將0和1都歸類爲1,只將-1歸爲-1。
    • 再次使用NULLIF從COUNT()中移除1,因爲我們只需要計算負數。
    • % 2靠在計數()負數的返回任一
    • - > 1,如果有奇數個負數
    • - > 0,如果有偶數個負數
    • 更數學招數:我們取1或0斷0.5,使得上述變
    • - >(0.5-1=-0.5 =>輪-1),如果有奇數個負數
    • - >(0.5-0= 0.5 =>輪到)如果有偶數個負數
    • 我們多這最後的1/-1危害的真實結果
+0

請參閱此爲零和負處理的不同方式:http://stackoverflow.com/questions/3653586 – gbn 2011-05-20 04:56:28

+0

爲避免ANSI警告關於從集合或SET運算符中刪除的NULL值,您可以用COUNT(CASE當SIGN(SIGN(data)+0.5)替換count(nullif(sign(sign(data)+0.5),1))' > 1 THEN 1 END)'。在執行查詢之前,您還可以「設置ANSI_WARNINGS OFF」,但我更願意編寫查詢,以便它不會首先產生警告。 – 2014-02-23 18:22:02

+0

有趣的是,EXP(SUM(Log(abs(nullif(data,0)))))'中的NULLIF(data,0)對於它的工作是必要的,即使CASE語句應該返回0而不評估ELSE部分。如果數據集中存在零值,則省略NULLIF(數據0)會導致域錯誤。 – 2014-02-23 20:23:56

-1

不確定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) 
20

否積和值,但是你可以用數學:)

如果yourColumn總是大於零:

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

Konerak EXP ***是***'e'。 http://msdn.microsoft.com/en-us/library/ms179857.aspx。它是自然日誌的EXP-onent,它與LOG – RichardTheKiwi 2011-03-24 08:06:31

+0

-1「ORA-00909:無效參數數量」配對。編輯:哎呀,我發現它不是一個Oracle的問題...我已經撤消了我的-1。 – 2011-03-24 08:12:35

1

在PostgreSQL,您可以創建自己的聚合函數,請參閱

要在MySQL上創建一個聚合函數,您需要構建一個.so(linux)或.dll(windows)文件。示例如下:http://www.codeproject.com/KB/database/mygroupconcat.aspx

我不確定mssql和oracle,但我敢打賭他們也有創建自定義聚合的選項。

6

我看到一個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. 

問候,
羅布。

1

隨着數字的增加,您會很快破壞任何數據類型。

使用LOG/EXP爲棘手由於數字< = 0,使用LOG時將失敗。我寫了this question一個解決方案,與此

0

在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