繁体   English   中英

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

[英]How to define own aggregate function in Mysql for GROUP BY?

我有一个products表,其中的产品名称使用不同的语言:

product-id | lang-no | name

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

我没有所有产品名称的所有语言,因此有时我不得不使用另一种语言。

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

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

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

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

您可以将case与聚合一起使用,以指定返回的值(如果存在)和最小(或最大值)值:

select p.*
from products p
join (
    select product_id,
        case 
            when sum(lang_no = 3) > 0
                then 3
            else min(lang_no)
            end as min_lang_no
    from products
    group by product_id
    ) p2 on p.product_id = p2.product_id
    and p.lang_no = p2.min_lang_no

下面将以首选语言选择name 如果该名称无法使用首选语言显示,则它将选择lang_no值最大的一种lang_no

SELECT product_id,
       langNum,
       name
FROM ( SELECT products.product_id AS product_id,
              CASE
                  WHEN hasPreferredLang = 0 THEN
                      maxLangNum
                  ELSE
                      preferredLang
              END AS langNum
       FROM ( SELECT product_id AS product_id,
                     MAX( lang_no ) AS maxLangNum
              FROM products
              GROUP BY product_id
            ) AS maxLangNumFinder
       JOIN ( SELECT product_id AS product_id,
                     SUM( CASE
                              WHEN lang_no = preferredLang THEN
                                  1
                              ELSE
                                  0
                          END ) AS hasPreferredLang
              FROM products
              GROUP BY product_id
            ) AS hasPreferredLangFinder ON hasPreferredLang.product_id = maxLangNumFinder.product_id
     ) AS preferredLangNumFinder
JOIN products ON preferredLangNumFinder.langNum = products.lang_no
                 preferredLangNumFinder.product_id = products.product_id;

该语句首先确定product_id每个值lang_no的最大可用值是lang_no 这样,我们就可以确定lang_no的值,以便在product_id没有首选语言条目的情况下使用。

然后将此子查询与另一个列出每个product_id以及值0子查询进行INNER JOIN编程,以指示product_id是否不具有与其相关联的首选语言或在其中具有1

然后,将子查询的结果用于测试每个product_id是否具有首选语言。 如果是这样,则返回首选语言。 如果不是,则使用lang_no的最大可用值。

将所得的列表product_id值和它们的选择lang_no值然后INNER JOIN编到products上的共享值product_idlang_no ,与product_id ,选择lang_noname为所选择的语言是SELECT从所得数据集编

如果您有任何问题或意见,请随时发表评论。

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

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;

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

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
                  );

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

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

一个警告是应该列出所有语言,因为缺少的值将为0。如果这是一个问题,请使用以下逻辑:

field(lang_no, 1, 3) desc

这会将3作为第一优先级,将1作为第二优先级,然后再进行其他处理。

SELECT p1.*
FROM products p1
WHERE p1.lang_no = (
    SELECT p2.lang_no
    FROM products p2
    WHERE p2.product_id = p1.product_id
    ORDER BY p2.lang_no = 3 DESC, p2.lang_no ASC
    LIMIT 1
);

如果该产品的lang_no存在,则相关的子查询将返回3否则返回最少的long_no

您的方法是错误的,违反了数据库结构和规范化规则。

由于许多语言都有许多产品,因此我建议您为产品和语言创建两个单独的表,并通过身份表将它们链接起来。

所以我建议:

Product:
ProductId ProductName

Language:
LanguageId LanguageName

Product_Lanugage:
ProductId Languageid

查询将是这样的:

SELECT * FROM products p INNER JOIN
Product_language pl on p.productid=pl.prouctid 
INNER JOIN language l on l.lanugageid=pl.languageid
where l.languagename like %(anylanuage)%

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM