因为循环的建议意味着需要一种过程类型的解决方案。这是我的解决方案。
任何作用于表中单个记录的查询都可以被包装在一个过程中,使其遍历表中的每一行,如下所示:
首先删除具有相同名称的任何现有过程,并更改分隔符,以便您的SQL不会尝试将每行作为您尝试编写过程而运行。
DROP PROCEDURE IF EXISTS ROWPERROW;
DELIMITER ;;
那么这里是按照您的示例进行操作的步骤(为了清晰起见使用table_A和table_B)
CREATE PROCEDURE ROWPERROW()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM table_A INTO n;
SET i=0;
WHILE i<n DO
INSERT INTO table_B(ID, VAL) SELECT (ID, VAL) FROM table_A LIMIT i,1;
SET i = i + 1;
END WHILE;
End;
;;
那么不要忘记重置分隔符
DELIMITER ;
并运行新的过程
CALL ROWPERROW();
在这个例子中,你可以随意更改“INSERT INTO”行,我只是从你的请求示例中复制过来。
请仔细注意,“INSERT INTO”行与问题中的行相同。根据此答案的评论,您需要确保您的查询在运行的任何SQL版本中语法正确。
在ID字段递增且从1开始的简单情况下,示例中的行可能会变为:
INSERT INTO table_B(ID, VAL) VALUES(ID, VAL) FROM table_A WHERE ID=i;
用以下内容替换“SELECT COUNT”行
SET n=10
只会让您测试table_A表中前10条记录的查询。
最后一件事,这个过程很容易嵌套在不同的表之间,并且是我能够在一个表格上执行一个进程的唯一方法,该表从父表的每一行动态插入不同数量的记录到新表格中。
如果您需要更快的运行速度,那么可以尝试使其基于设置,否则这样就可以了。您还可以以游标形式重写上述内容,但这可能不会提高性能。例如:
DROP PROCEDURE IF EXISTS cursor_ROWPERROW;
DELIMITER ;;
CREATE PROCEDURE cursor_ROWPERROW()
BEGIN
DECLARE cursor_ID INT;
DECLARE cursor_VAL VARCHAR;
DECLARE done INT DEFAULT FALSE;
DECLARE cursor_i CURSOR FOR SELECT ID,VAL FROM table_A;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cursor_i;
read_loop: LOOP
FETCH cursor_i INTO cursor_ID, cursor_VAL;
IF done THEN
LEAVE read_loop;
END IF;
INSERT INTO table_B(ID, VAL) VALUES(cursor_ID, cursor_VAL);
END LOOP;
CLOSE cursor_i;
END;
;;
记得将要使用的变量声明为与查询表中的变量类型相同。
我的建议是,如果可以,请选择基于集合的查询,只有在必要时才使用简单循环或光标。