如何在Mysql中为GROUP BY定义自己的聚合函数?

Gen*_*ent 5 mysql sql group-by aggregate-functions

我有一个products表格,其中包含不同语言的产品名称:

product-id | lang-no | name
Run Code Online (Sandbox Code Playgroud)

我想列出每个产品一次,但使用不同的语言名称.

我没有所有产品名称的所有语言,所以我有时会回到另一种语言.

选择我使用的最低或最高数字的语言

SELECT * FROM products JOIN
(SELECT product-id, MIN(lang-no) AS minlang FROM products GROUP BY product-id)
AS u ON products.product-id = u.product-id AND products.lang-no=minlang
Run Code Online (Sandbox Code Playgroud)

但是现在我需要定义另一个聚合函数而不是MIN或MAX,所以我更喜欢lang-no 3.

我如何在Mysql中定义自己的聚合函数,例如.一些IF逻辑?

Gor*_*off 1

如果您希望每个产品出现一次,那么一种方法是使用变量:

select p.*
from (select p.*,
             (@rn := if(@pid = p.product_id, @rn + 1,
                        if(@pid := p.product_id, 1, 1)
                       )
             ) as rn
      from products p cross join
           (select @pid := -1, @rn := 0) params
      order by product_id, field(lang_no, 3, 4, 1, 5, 2) -- or whatever
     ) p
where rn = 1;
Run Code Online (Sandbox Code Playgroud)

另一种方法使用相关子查询:

select p.*
from products p
where p.lang_no = (select p2.lang_no
                   from products p2
                   where p2.product_id = p.product_id
                   order by field(lang_no, 3, 4, 1, 5, 2)  -- or whatever
                   limit 1
                  );
Run Code Online (Sandbox Code Playgroud)

这两个版本都使用field(). 这允许您列出所有语言及其优先级。

在您的情况下,假设您在 上有索引,相关子查询可能会更快product_id

需要注意的是,应列出所有语言,因为缺失值会为 0。如果这是一个问题,请使用以下逻辑:

field(lang_no, 1, 3) desc
Run Code Online (Sandbox Code Playgroud)

这会将 3 设置为第一优先级,将 1 设置为第二优先级,然后再设置其他优先级。