在mysql中创建一个与groupby一起使用的用户定义函数

m3eecexj  于 2021-06-17  发布在  Mysql
关注(0)|答案(2)|浏览(309)

我正在尝试在mysql中创建一个聚合函数median(),比如min()、max()、avg(),它将输入的列名或字符串与所需列的值串联在一起。
我很难理解mysql自定义函数的局限性&如果有人能帮我找出这是如何做到的,那将非常有帮助。
例子:
mysql表有2列(id,num)

+----+-----+
| id | num |
+----+-----+
|  1 |   5 |
|  1 |   6 |
|  1 |   7 |
|  2 |   1 |
|  2 |   3 |
|  2 |   5 |
+----+-----+
SELECT id, MEDIAN(num) as median
FROM table
GROUP BY id;

或者

SELECT id, MEDIAN(GROUP_CONCAT(num SEPARATOR ',') as median
FROM table
GROUP BY id;

预期输出为

+----+--------+
| id | median |
+----+--------+
|  1 |      6 |
|  2 |      3 |
+----+--------+
8ehkhllq

8ehkhllq1#

mariadb-10.3.3中增加了用户定义的聚合存储函数
mysql可以执行聚合函数,但不能在sql中执行。他们需要一个udf(共享库实现)

myzjeezk

myzjeezk2#

没有自定义项是可以做到的,我知道有两种方法。第一种方法使用两个select和一个join,第一个select获取值和排名,第二个select获取计数,然后将它们合并。第二种方法使用json函数在一个select中获取所有内容。它们都有点长,但它们工作起来很快。
解决方案#1(两个选择和一个连接,一个获得计数,一个获得排名)

SELECT  x.group_field, 
        avg(
            if( 
                x.rank - y.vol/2 BETWEEN 0 AND 1, 
                value_field, 
                null
            )
        ) as median
FROM (
    SELECT  group_field, value_field, 
            @r:= IF(@current=group_field, @r+1, 1) as rank, 
            @current:=group_field
    FROM (
        SELECT group_field, value_field
        FROM table_name
        ORDER BY group_field, value_field
    ) z, (SELECT @r:=0, @current:='') v
) x, (
    SELECT group_field, count(*) as vol 
    FROM table_name
    GROUP BY group_field
) y WHERE x.group_field = y.group_field
GROUP BY x.group_field;

解决方案#2(使用json对象存储计数并避免连接)

SELECT group_field, 
    avg(
        if(
            rank - json_extract(@vols, path)/2 BETWEEN 0 AND 1,
            value_field,
            null
        )
    ) as median
FROM (
    SELECT group_field, value_field, path, 
        @rnk := if(@curr = group_field, @rnk+1, 1) as rank,
        @vols := json_set(
            @vols, 
            path, 
            coalesce(json_extract(@vols, path), 0) + 1
        ) as vols,
        @curr := group_field
    FROM (
        SELECT p.group_field, p.value_field, concat('$.', p.group_field) as path
        FROM table_name
        JOIN (SELECT @curr:='', @rnk:=1, @vols:=json_object()) v
        ORDER BY group_field, value_field DESC
    ) z
) y GROUP BY group_field;

相关问题