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
函数将其切换回来,但这并没有什么区别。我还尝试使用WHERE
和HAVING
作为条件子句,但都没有奏效。我还进行了广泛的网络搜索,但找不到任何有用的东西。
我不知道还能尝试什么,主要是因为我看不出这里的语法有什么问题。任何帮助将不胜感激。
更新 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 关于需要使用 SELECT
和 GROUP_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' 错误,不涉及聚合函数的主要内容,如果未能解决你的问题,请参考以下文章