MySQL GROUP_CONCAT 'Invalid use of Group function' 不涉及聚合函数的错误
MySQL GROUP_CONCAT 'Invalid use of Group function' error that DOESN'T involve an aggregate function
我有一个 MySQL 存储过程(如下所示),它应该从 table 层级相关记录构建 ID 列表。我不得不重新设计一个较旧的存储过程,以从使用简单的 CONCAT 函数切换到 GROUP_CONCAT,因为前者无法处理正在生成的列表的大小(即,列表在CONCAT 函数的 1024 个字符限制)。
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 ;
问题是当我尝试调用此例程时生成以下错误(有时 returns 当我尝试创建存储过程时出现此错误):
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 '');
但这也没什么区别。
您不能将 GROUP_CONCAT()
用作标量函数;它必须在一组行的上下文中使用。同样,如果没有 table 引用,则不能使用任何其他聚合函数:
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;
这将消除使用循环或 prepare/execute 或临时变量的需要。
感谢 Bill Karwin 关于需要将 SELECT
与 GROUP_CONCAT
一起使用的回答,我能够看到我的代码需要如何更改。我不需要使用 SET
语句来为变量赋值,而是需要使用 SELECT ... INTO ...
结构,如下所示:
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 存储过程(如下所示),它应该从 table 层级相关记录构建 ID 列表。我不得不重新设计一个较旧的存储过程,以从使用简单的 CONCAT 函数切换到 GROUP_CONCAT,因为前者无法处理正在生成的列表的大小(即,列表在CONCAT 函数的 1024 个字符限制)。
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 ;
问题是当我尝试调用此例程时生成以下错误(有时 returns 当我尝试创建存储过程时出现此错误):
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 '');
但这也没什么区别。
您不能将 GROUP_CONCAT()
用作标量函数;它必须在一组行的上下文中使用。同样,如果没有 table 引用,则不能使用任何其他聚合函数:
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;
这将消除使用循环或 prepare/execute 或临时变量的需要。
感谢 Bill Karwin 关于需要将 SELECT
与 GROUP_CONCAT
一起使用的回答,我能够看到我的代码需要如何更改。我不需要使用 SET
语句来为变量赋值,而是需要使用 SELECT ... INTO ...
结构,如下所示:
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 ;
这现在产生了我正在寻找的结果。当然,递归查询方法是我想要做的更好的解决方案,但也许我的解决方案会对其他人有所帮助。