由于循环的建议意味着对过程类型解决方案的请求。这是我的。
任何适用于从表中获取的任何单个记录的查询都可以包装在一个过程中,以使其遍历表的每一行,如下所示:
首先删除任何具有相同名称的现有过程,并更改分隔符,以便您的 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;
;;
请记住将您将使用的变量声明为与查询表中的变量相同的类型。
我的建议是尽可能使用基于集合的查询,并且在必要时仅使用简单的循环或游标。