【问题标题】:Using GROUP_CONCAT, GROUP, and HAVING in the same statement in MySQL在 MySQL 的同一语句中使用 GROUP_CONCAT、GROUP 和 HAVING
【发布时间】:2015-03-17 14:30:35
【问题描述】:

在应用程序中,有表 projectscategories 和一个表,用于处理它们之间的 n:m 关系 (project_category_info):

现在我想获取一个类别的所有项目(我正在使用HAVING 解决这个问题)。我还需要结果集中的信息,每个项目属于哪些类别(CONCAT_GROUP 结合GROUP):

SELECT
    `projects`.*,
    `categories`.`id` AS `id`,
    GROUP_CONCAT(categories.id SEPARATOR '|||') AS `categories`,
    GROUP_CONCAT(categories.short_name SEPARATOR '|||') AS `category_names`
FROM
    `projects`
INNER JOIN
    `project_category_info` ON `project_category_info`.`project_id` = `projects`.`id`
LEFT JOIN
    `categories` ON `project_category_info`.`category_id` = `categories`.`id`
GROUP BY
    `projects`.`id`
HAVING
    (`categories`.`id` = 3)
;

结果集包含 13 行。但是当我省略GROUP_CONCATGROUP 时,我会多得到一排。为什么?什么会导致这种行为?

【问题讨论】:

  • 您能否提供一些显示SQL Fiddle? 中行为的示例数据另外,上述查询是错误的。您不能将HAVING 用于不使用任何聚合函数的条件。将该条件移至WHERE 子句。也许这就是问题所在?
  • 这是一个糟糕的错误查询(两个错误,因为它有两个问题)。如果您的意图是在结果集中包含 category_id,那么它必须在您的 GROUP BY 子句中。任何其他 RDBMS 都会简单地出错,但 MySQL 很疯狂,所以它让你做这些废话(而且这是废话)。其次,使用 WHERE 子句而不是 HAVING。 HAVING 在聚合之后应用,并且由于您的聚合是无意义的(参见第 1 点),因此您的结果将是无意义的。
  • @McAdam331 非常感谢您的评论!我将WHERE 替换为HAVING 以过滤分组后的数据。我不记得了,但 WHERE 有什么问题。现在我又用WHERE 尝试了这个——它有效!请发表您的建议作为答案。
  • @JNevill 谢谢你的解释。实际上我不想在我的结果集中有一个category_id,因为每个项目都属于多个类别。
  • @McAdam331 & @JNevill HAVING:伙计们,你是对的,HAVING 应该用于聚合数据。但是GROUP_CONCAT 一个聚合函数。现在我知道了,为什么我用HAVING 替换了WHEREWHERE 在分组之前 过滤数据。这意味着,我的 GROUP_CONCAT 不起作用,我的列 category_name 包含所有选定行的相同类别名称。

标签: mysql sql group-by group-concat having-clause


【解决方案1】:

我开始相信你的逻辑在你的查询中是错误的。我建议尝试重写它。最好的方法是退后一步,把问题分解,然后再把它重新组合起来。

获取一个类别的所有项目:

SELECT project_id
FROM project_category_info
WHERE category_id = 3;

现在,将其连接回 category_info 表以获取这些项目的所有行:

SELECT *
FROM project_category_info
WHERE project_id IN(
   SELECT project_id
   FROM project_category_info
   WHERE category_id = 3);

您可以将其加入项目和类别以获取名称:

SELECT p.id, p.title, c.title
FROM project_category_info pci
JOIN projects p ON p.id = pci.project_
JOIN categories c ON c.id = pci.catgory_id
WHERE pci.project_id IN(
   SELECT project_id
   FROM project_category_info
   WHERE category_id = 3);

现在,您可以将 GROUP_CONAT() 添加到 c.title 列,并按 p.id 分组:

SELECT p.id, p.title, GROUP_CONCAT(c.short_name SEPARATOR '|||') AS category_names
FROM project_category_info pci
JOIN projects p ON p.id = pci.project_
JOIN categories c ON c.id = pci.catgory_id
WHERE pci.project_id IN(
   SELECT project_id
   FROM project_category_info
   WHERE category_id = 3)
GROUP BY p.id;

【讨论】:

  • 它没有按预期工作,请查看我的comment
  • @automatix 好的,我尝试了完全不同的方法。
  • 我编辑了您的问题 - 对其进行了格式化,以便更好地与原始代码进行比较,并修复了一些拼写错误。但这些变化似乎被拒绝了。
  • 我用一些数据构建了一个示例数据库。不幸的是,我们的语句(my original oneyours)返回相同的结果。无论如何,我刚刚尝试了您的第二个解决方案 - 它似乎有效!谢谢!
  • @automatix 很高兴我能帮上忙!如果您使用该解决方案,请随意点赞并接受它,这样未来的读者就会知道是什么解决了您的问题。
猜你喜欢
  • 2011-12-16
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-09
相关资源
最近更新 更多