MySQL 将准备好的语句与 CONCAT 一起使用时出现语法错误
MySQL syntax error when using prepared statement with CONCAT
我正在尝试在存储过程中使用准备好的语句。我在初始 SET @idToUpdateQuery
中遇到语法错误。我已经知道 CONCAT
没有使用 :=
的变量赋值可以正常工作,因为它在其他地方使用并且按预期工作。本质上,我只需要能够将准备好的 SELECT 语句的结果放入变量 @resultId
中。有问题的代码如下:
SET @distinctTableXIds = (SELECT COUNT(*) FROM tempTableX);
SET @i = 0;
WHILE @i < @distinctTableXIds DO
/*CONCAT IS NEEDED HERE TO PASS USER DEFINED @i*/
SET @idToUpdateQuery = CONCAT('SELECT @result := MAX(id)
FROM tableY
WHERE tableZId = (SELECT id FROM tempTableX ORDER BY id LIMIT ', @i, ', 1)');
PREPARE @IdToUpdateStmt FROM @IdToUpdateQuery;
EXECUTE @IdToUpdateStmt;
SET @resultId = SELECT @result;
UPDATE tableY
SET someBoolean = 1
WHERE id = @resultId;
SET @i = @i + 1;
END WHILE;
您不使用 @
印记作为语句名称。它不是用户变量。
参见 https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html
中的示例
mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
除此之外,我认为您根本不需要为此任务准备好的语句。我可以想到至少两个其他解决方案。给我几分钟,我会写一篇。
一种使用游标的解决方案(参见https://dev.mysql.com/doc/refman/8.0/en/cursors.html):
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE max_id INT;
DECLARE cur1 CURSOR FOR SELECT MAX(id) FROM tableY JOIN tempTableX ON (tableY.tableZId = temptableX.id) GROUP BY tableZId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO max_id
IF done THEN
LEAVE read_loop;
END IF;
UPDATE tableY SET someBoolean = 1 WHERE id = max_id;
END LOOP;
CLOSE cur2;
END
另一种在一条 UPDATE 语句中完成所有工作的解决方案:
UPDATE tableY AS y1
INNER JOIN tempTableX AS x ON (y1.tableZId = x.id)
LEFT OUTER JOIN tableY AS y2 ON (y1.tableZId = y2.tableZId AND y1.id < y2.id)
SET y1.someBoolean = 1
WHERE y2.id IS NULL;
外连接技巧是一种查找 y1 的行的方法,其中不存在具有相同 tableZId
和更大 id
的行。换句话说,它为具有给定 tableZId
.
的每组行找到最大的 id
我正在尝试在存储过程中使用准备好的语句。我在初始 SET @idToUpdateQuery
中遇到语法错误。我已经知道 CONCAT
没有使用 :=
的变量赋值可以正常工作,因为它在其他地方使用并且按预期工作。本质上,我只需要能够将准备好的 SELECT 语句的结果放入变量 @resultId
中。有问题的代码如下:
SET @distinctTableXIds = (SELECT COUNT(*) FROM tempTableX);
SET @i = 0;
WHILE @i < @distinctTableXIds DO
/*CONCAT IS NEEDED HERE TO PASS USER DEFINED @i*/
SET @idToUpdateQuery = CONCAT('SELECT @result := MAX(id)
FROM tableY
WHERE tableZId = (SELECT id FROM tempTableX ORDER BY id LIMIT ', @i, ', 1)');
PREPARE @IdToUpdateStmt FROM @IdToUpdateQuery;
EXECUTE @IdToUpdateStmt;
SET @resultId = SELECT @result;
UPDATE tableY
SET someBoolean = 1
WHERE id = @resultId;
SET @i = @i + 1;
END WHILE;
您不使用 @
印记作为语句名称。它不是用户变量。
参见 https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html
中的示例mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
除此之外,我认为您根本不需要为此任务准备好的语句。我可以想到至少两个其他解决方案。给我几分钟,我会写一篇。
一种使用游标的解决方案(参见https://dev.mysql.com/doc/refman/8.0/en/cursors.html):
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE max_id INT;
DECLARE cur1 CURSOR FOR SELECT MAX(id) FROM tableY JOIN tempTableX ON (tableY.tableZId = temptableX.id) GROUP BY tableZId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO max_id
IF done THEN
LEAVE read_loop;
END IF;
UPDATE tableY SET someBoolean = 1 WHERE id = max_id;
END LOOP;
CLOSE cur2;
END
另一种在一条 UPDATE 语句中完成所有工作的解决方案:
UPDATE tableY AS y1
INNER JOIN tempTableX AS x ON (y1.tableZId = x.id)
LEFT OUTER JOIN tableY AS y2 ON (y1.tableZId = y2.tableZId AND y1.id < y2.id)
SET y1.someBoolean = 1
WHERE y2.id IS NULL;
外连接技巧是一种查找 y1 的行的方法,其中不存在具有相同 tableZId
和更大 id
的行。换句话说,它为具有给定 tableZId
.
id