Mysql

如何創建使用者定義的聚合函式?

  • April 7, 2021

我需要一個 MySQL 不提供的聚合函式。

我希望它具有 MySQL 的 SQL 風格(也就是說,不是 C 語言)。

我該怎麼做呢?我堅持的是創建一個聚合函式——文件似乎沒有提到這是如何完成的。

函式的期望用法範例product

mysql> select product(col) as a from `table`;
+------+
| a    |
+------+
|  144 |
+------+
1 row in set (0.00 sec)

mysql> select col, product(col) as a from `table` group by col;
+-----+------+
| col | a    |
+-----+------+
|   6 |   36 |
|   4 |    4 |
+-----+------+
2 rows in set (0.01 sec)

根據文件http://dev.mysql.com/doc/refman/5.5/en/adding-udf.html只能用 C 編寫聚合函式。對不起!

我不知道是否有辦法定義一個新的聚合函式,而不是弄亂 MySQL 原始碼。

但如果你的數字都是正數,你很可能從算術恆等式中推導出來:

log( product( Ai ) ) = sum( log( Ai ) )

可以EXP(SUM(LOG(x)))用來計算PRODUCT(x)。在SQL-Fiddle中測試:

SELECT EXP(SUM(LOG(a))) AS product
FROM t ;

SELECT col, EXP(SUM(LOG(a))) AS product
FROM t 
GROUP BY col ;

當數據可以有 0 時,它會變得有點複雜:

SELECT (NOT EXISTS (SELECT 1 FROM t WHERE a = 0)) 
      * EXP(SUM(LOG(a))) AS p
FROM t 
WHERE a > 0 ;

SELECT d.col, 
      (NOT EXISTS (SELECT 1 FROM t AS ti WHERE ti.col = d.col AND ti.a = 0)) 
      * COALESCE(EXP(SUM(LOG(t.a))),1)  AS p
FROM 
   ( SELECT DISTINCT col
     FROM t
   ) AS d
 LEFT JOIN
   t  ON  t.col = d.col
      AND t.a > 0
GROUP BY d.col ;

在**SQL-Fiddle測試**


對於其他沒有 MySQL 將布爾值自動轉換為整數的 DBMS,

(NOT EXISTS (SELECT ...))

應替換為:

(CASE WHEN EXISTS (SELECT 1...) THEN 0 ELSE 1 END) 

特別是對於Oracle,需要再做一些更改,而不改變答案的邏輯,只是因為Oracle在某些方面沒有遵循嚴格的ANSI標準。在**SQL-Fiddle-2測試**

引用自:https://dba.stackexchange.com/questions/17267