use*_*182 9 mysql stored-procedures
我有两张桌子:
people_en: id, name
people_es: id, name
Run Code Online (Sandbox Code Playgroud)
(请不要理会规范化.设计是规范化的.表格要比这复杂得多,但这只是简化问题的一种方法).
然后我有一个存储过程:
CREATE PROCEDURE myproc(lang char(2))
BEGIN
set @select = concat('SELECT * FROM ', lang, ' limit 3');
PREPARE stm FROM @select;
EXECUTE stm;
DEALLOCATE PREPARE stm;
SET @cnt = FOUND_ROWS();
SELECT @cnt;
IF @cnt = 3 THEN
//Here I need to loop through the rows
ELSE
//Do something else
END IF;
END$$
Run Code Online (Sandbox Code Playgroud)
或多或少,程序中的逻辑是:
如果select给出3行,那么我们必须循环遍历行并使用每行中的值执行某些操作.别的什么东西(不重要的是什么,但是我把这个让你明白我需要在循环之前有一个if语句.
我已经看过并阅读过关于游标的内容,但是找不到由concat创建的选项(这有关系吗?),尤其是使用准备好的语句创建的.如何遍历结果列表并使用每行的值?谢谢.
小智 15
我有一些坏消息和好消息.
首先是坏消息.
MySQL手册说游标不能用于使用PREPARE和EXECUTE准备和执行的动态语句.在游标创建时检查游标的语句,因此该语句不能是动态的.
所以到目前为止还没有动态游标......在这里你需要这样的东西.
但现在好消息是:至少有两种方法可以绕过它 - 使用vw或tbl.
下面我重写了你的代码和应用视图来制作'动态'光标.
DELIMITER //
DROP PROCEDURE IF EXISTS myproc;
CREATE PROCEDURE myproc(IN lang VARCHAR(400))
BEGIN
DECLARE c VARCHAR(400);
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE cur CURSOR FOR SELECT name FROM vw_myproc;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SET @select = concat('CREATE VIEW vw_myproc as SELECT * FROM ', lang, ' limit 3');
PREPARE stm FROM @select;
EXECUTE stm;
DEALLOCATE PREPARE stm;
SET @select = concat('SELECT * FROM ', lang, ' limit 3');
PREPARE stm FROM @select;
EXECUTE stm;
DEALLOCATE PREPARE stm;
SET @cnt = FOUND_ROWS();
SELECT @cnt;
IF @cnt = 3 THEN
OPEN cur;
read_loop: LOOP
FETCH cur INTO c;
IF done THEN
LEAVE read_loop;
END IF;
#HERE YOU CAN DO STH WITH EACH ROW e.g. UPDATE; INSERT; DELETE etc
SELECT c;
END LOOP read_loop;
CLOSE cur;
DROP VIEW vw_myproc;
ELSE
SET c = '';
END IF;
END//
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)
并测试程序:
CALL myproc('people_en');
Run Code Online (Sandbox Code Playgroud)
小智 5
@clickstefan,您将遇到两个或更多用户同时尝试执行脚本的问题.第二个用户将收到该行的"查看vw_myproc已存在"错误消息:
SET @select = concat('CREATE VIEW vw_myproc as SELECT * FROM ', lang, ' limit 3');
Run Code Online (Sandbox Code Playgroud)
解决方案是临时表 - 它仅存在于当前连接的生命周期中,用户可以同时创建具有相同名称的临时表.因此,代码可能如下所示:
DROP TABLE IF EXISTS vw_myproc;
SET @select = concat('CREATE TEMPORARY TABLE vw_myproc AS SELECT * FROM ', lang, ' limit 3');
Run Code Online (Sandbox Code Playgroud)