MySQL GROUP_CONCAT 'Invalid use of Group function' 错误,不涉及聚合函数

Posted

技术标签:

【中文标题】MySQL GROUP_CONCAT \'Invalid use of Group function\' 错误,不涉及聚合函数【英文标题】:MySQL GROUP_CONCAT 'Invalid use of Group function' error that DOESN'T involve an aggregate functionMySQL GROUP_CONCAT 'Invalid use of Group function' 错误,不涉及聚合函数 【发布时间】:2021-12-31 05:39:04 【问题描述】:

我有一个 mysql 存储过程(如下所示),它应该从分层相关记录表中构建一个 ID 列表。我不得不重新设计一个较旧的存储过程,从使用简单的 CONCAT 函数切换到 GROUP_CONCAT,因为前者无法处理正在生成的列表的大小(即,列表远远超过了 1024 个字符的限制CONCAT 函数)。

DELIMITER $$
CREATE PROCEDURE SPTest (top_id INT)
BEGIN
    DECLARE ids_all TEXT;
    SET SESSION group_concat_max_len = 1000000;
    SET ids_all = top_id;
    SET @str = GROUP_CONCAT('SELECT GROUP_CONCAT(id SEPARATOR \', \') ',
        'FROM tbl WHERE nha_id = ', top_id, ' INTO @ids_tmp' SEPARATOR '');
    PREPARE stmt FROM @str;
    EXECUTE stmt;
    WHILE @ids_tmp != "" DO
        SET ids_all = GROUP_CONCAT(ids_all, @ids_tmp SEPARATOR ', ');
        SET @str = GROUP_CONCAT('SELECT GROUP_CONCAT(id SEPARATOR \', \') ',
            'FROM tbl WHERE nha_id IN (', @ids_tmp, ') INTO @ids_tmp' SEPARATOR '');
        PREPARE stmt FROM @str;
        EXECUTE stmt;
    END WHILE;
    SELECT ids_all AS ids;
END $$
DELIMITER ;

问题是这个例程在我尝试调用它时会产生以下错误(有时它会在我尝试创建存储过程时返回此错误):

ERROR 1111 (HY000): Invalid use of group function

当我手动创建与此代码相同类型的查询并在命令行中运行它们时,它们工作得非常好——没有任何类型的错误,而且我得到了我期望的结果。我已经看到帖子(在 Stack Exchange 和其他地方)说 MySQL 不支持嵌套聚合函数,但这里的连接只是对字符串进行。所以我认为它可能以某种方式在字符串中看到了GROUP_CONCAT 并因此而打嗝,所以我尝试在字符串中放入“XXXX”代替“GROUP_CONCAT”,然后使用REPLACE 函数将其切换回来,但这并没有什么区别。我还尝试使用WHEREHAVING 作为条件子句,但都没有奏效。我还进行了广泛的网络搜索,但找不到任何有用的东西。

我不知道还能尝试什么,主要是因为我看不出这里的语法有什么问题。任何帮助将不胜感激。

更新 1:

此后,我尝试了脚本的修改版本,其中GROUP_CONCAT 合并来自子查询的数据,如下所示:

SET @qrystr = GROUP_CONCAT('SELECT GROUP_CONCAT(c SEPARATOR ", ") ',
    'FROM (SELECT id AS c FROM tbl WHERE nha_id IN (', @ids_tmp, 
    ') AS d INTO @ids_tmp' SEPARATOR '');

但这也没什么区别。

【问题讨论】:

【参考方案1】:

您不能将GROUP_CONCAT() 用作标量函数;它必须在一组行的上下文中使用。同样,您不能在没有表引用的情况下使用任何其他聚合函数:

SET @x = MAX(<expr>); -- makes no sense

如果您还没有升级到 MySQL 8.0,理想情况下应该使用 recursive CTE query 代替:

WITH RECURSIVE hierarchy AS (
  SELECT top_id AS id
  UNION
  SELECT tbl.id FROM tbl JOIN hierarchy ON tbl.nha_id = hierarchy.id
)
SELECT GROUP_CONCAT(id SEPARATOR ', ') AS ids_all FROM hierarchy;

这将消除使用循环或准备/执行或临时变量的需要。

【讨论】:

实际上你可以加入字符串文字。当我说“当我手动创建相同类型的查询时,此代码将在命令行中构建并运行它们,它们工作得非常好”,这正是我所做的——我输入了“SELECT GROUP_CONCAT('SELECT GROUP_CONCAT (id SEPARATOR \', \') ', 'FROM tbl WHERE nha_id IN (', @ids_tmp, ')' SEPARATOR '');"并得到了我正在寻找的确切结果。话虽如此,我不知道 RECURSIVE CTE 查询,但我确实有 MySQL 8.0。这可能很好地解决了我的问题,但要等到明天早上我才能尝试! 是的,您可以将字符串文字传递给 GROUP_CONCAT() 但您不能将其用作纯表达式而不是 SELECT 语句的一部分。 这就是问题所在。感谢您指出了这一点。请参阅我的答案和修改后的代码。并感谢有关递归 CTE 查询的信息;效果很好。【参考方案2】:

感谢 Bill Karwin 关于需要使用 SELECTGROUP_CONCAT 的回答,我能够看到我的代码需要如何更改。我需要使用SELECT ... INTO ... 构造,而不是使用SET 语句将值分配给变量,如下所示:

DELIMITER $$
CREATE PROCEDURE ASSEMBLY_LIST_TEST (top_id INT)
BEGIN
    DECLARE ids_all TEXT DEFAULT '';
    SET SESSION group_concat_max_len = 1000000;
    SET ids_all = top_id;

    # Find the 1st-level children of 'top_id' to start building the list
    SELECT GROUP_CONCAT('SELECT GROUP_CONCAT(id SEPARATOR ", ") FROM tbl ',
        'WHERE nha_id = ', top_id, ' INTO @ids_tmp' SEPARATOR '') INTO @qrystr;
    PREPARE stmt FROM @qrystr;
    EXECUTE stmt;

    # Recursively find the children of each level of children of the previous loop & add to the list
    WHILE @ids_tmp != '' DO
        SELECT GROUP_CONCAT(ids_all, ', ', @ids_tmp SEPARATOR '') INTO ids_all;
        SELECT GROUP_CONCAT('SELECT GROUP_CONCAT(id SEPARATOR ", ") FROM tbl ',
            'WHERE nha_id IN (', @ids_tmp, ') INTO @ids_tmp' SEPARATOR '') INTO @qrystr;
        PREPARE stmt FROM @qrystr;
        EXECUTE stmt;
    END WHILE;
    SELECT ids_all AS ids;
END $$
DELIMITER ;

这会产生我想要的结果。当然,对于我想要做的事情,递归查询方法是一个更好的解决方案,但也许我的解决方案会对其他人有所帮助。

【讨论】:

以上是关于MySQL GROUP_CONCAT 'Invalid use of Group function' 错误,不涉及聚合函数的主要内容,如果未能解决你的问题,请参考以下文章

mysql 的group_concat方法

mysql用GROUP_CONCAT合并查询出现乱码?求大神!!!

mysql—group_concat函数

mysql查询结果拼接group_concat

mysql查询结果拼接group_concat

如何仅使用“group_concat”过滤表 mysql 中的行