[英]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_id
和lang_no
,与product_id
,选择lang_no
和name
为所选择的语言是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.