如何创建用户定义的聚合函数?


8

我需要一个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)

Answers:


7

根据文档http://dev.mysql.com/doc/refman/5.5/en/adding-udf.html,只能用C编写聚合函数。对不起!


C或C ++。无论如何,不​​是SQL。
Mike Sherrill'Cat Recall'

1
我假定任何语言都可以使用C调用约定以平台支持的二进制格式生成二进制库。
科林·哈特(

我不知道。在5.0版中,它被记录为“ C或C ++(或其他可以使用C调用约定的语言)”。文档在版本5.1中删除了“或可以使用C调用约定的另一种语言”。这是一个奇怪的短语。
Mike Sherrill'Cat Recall'2012年

现在(几年后)在最新的mysql版本中可用吗?
Dinesh

9

我不知道是否有办法定义一个新的聚合函数,而不是不弄乱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上测试


2
那真好;那真甜。高中数学又来困扰我了。+1 !!!
RolandoMySQLDBA 2012年

1
很酷的数学,但实际上我想知道如何创建聚合函数。 product本来只是几个例子中的一个。
马特·芬威克

这很酷,但是如果log(0)是未定义的,则如果任何值为零都行不通。
jameshfisher 2014年

@jameshfisher正确。可以轻松编写多余的条件,检查零(当然乘积为零)。我当时认为没有必要添加这种复杂性。
ypercubeᵀᴹ

我尚不清楚如何最好地添加该条件。我们不能在值的内部函数中添加条件:由于我们想要那个PRODUCT(..., 0, ...) = 0,我们想要那个EXP(SUM(..., f(0), ...)) = 0,对于f我们选择的一些东西,但是要满足这一点,我们需要那个SUM(..., f(0), ...) = LOG(0)-再次受到log(0 )未定义。我们需要以其他方式检查零的存在,例如MIN(ABS(a)) = 0。这样我们就可以了SELECT CASE WHEN MIN(ABS(a)) = 0 THEN 0 ELSE EXP(SUM(LOG(a))) END AS product。这是您正在考虑的事情吗?
jameshfisher 2014年

3

为了学习如何钓鱼,我成功地编译并安装了“ Hello,World!”。可在此处找到 MySQL的UDF(用户定义函数)。hello_world.so文件(遵循gcc -shared -o hello_world.so -I /usr/include/mysql hello_world.c)应在Ubuntu linux系统上以755权限存储在/ usr / lib / mysql / plugins /中。[“ -I / usr / include / mysql”是mysql头文件的路径;我发现如果没有该参数,我的代码将无法编译,但是会编译YMMV。]

该程序除了打印字符串“ Hello,World!”外什么也不做。对于查询的结果数据集中的每条记录,但这仅是应做的事情。在接下来的几天中,我将尝试编写一个小型聚合函数。有一个聚合函数的示例,该函数计算一组价格和数量记录的平均成本。最后,SMALL函数应该与该函数没有什么不同。

希望这可以帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.