将GROUP_CONCAT用作条件
我正在创建一个查询,其中有一个箱子,它包含多种产品。我想检查任意一个产品的product_numbers是否能在addons表中找到。因此我最初写了这个查询:
SELECT
b.name,
GROUP_CONCAT(DISTINCT p.number) product_numbers,
(
SELECT COUNT(id) FROM addons WHERE addons.product_code IN (product_numbers)
) `addon_count`
FROM box b
LEFT JOIN product p ON p.box_ident = b.ident
GROUP BY b.ident;
这段查询不起作用。我不确定接下来该怎么继续。如何根据product_numbers的值返回箱子中addons的数量?
解决方案
下面是一个解决方案:
SELECT
b.name,
GROUP_CONCAT(DISTINCT p.number) product_numbers,
COUNT(DISTINCT a.product_code) AS addon_count
FROM box b
LEFT JOIN product p ON p.box_ident = b.ident
LEFT JOIN addons a ON p.number = a.product_code
GROUP BY b.ident;
这个额外的连接确实会增加预聚合结果的行数,但两个聚合函数都使用 DISTINCT,因此在本例中可以抵消这一点。将来如果在聚合时不使用 DISTINCT 的查询中使用它,请记在心。
The addon_count 实际上并不真正统计addons,它统计的是在给定箱子中有至少一个addon的产品数量。看起来这就是如果你的查询能工作时它应该实现的效果。
演示:https://dbfiddle.uk/9-T9ICkb
你的查询在以下几个方面无法工作:
- GROUP_CONCAT() 返回的是一个用逗号分隔的字符串,而不是可用于
IN()谓词的列表。 - 在SELECT列表中的表达式不能引用同一SELECT列表中由另一表达式创建的别名(编辑:这对聚合表达式也成立,见下方Akina的评论)。
- 表达式的求值先后顺序未定义,因此你也不能指望在子查询被求值之前就先填充
product_numbers。
下面的示例展示了Barmar的注释所说的内容:
SELECT
t.name,
t.product_numbers,
COUNT(DISTINCT a.product_code) AS addon_count
FROM (
SELECT
b.ident,
b.name,
GROUP_CONCAT(DISTINCT p.number) product_numbers
FROM box b
LEFT JOIN product p ON p.box_ident = b.ident
GROUP BY b.ident
) t
LEFT JOIN addons a ON FIND_IN_SET(a.product_code, t.product_numbers)
GROUP BY t.ident;
这个查询仍然不能在同一个SELECT列表中引用聚合函数的结果,因此我们必须把前面的查询放到一个子查询中。
我不推荐这条查询。它有一个重要的缺点:FIND_IN_SET() 从不使用索引,因此对 addons 的连接很可能优化不佳。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。