Já a sugestão de um loop implica na solicitação de uma solução do tipo procedimento. Aqui é minha.
Qualquer consulta que funcione em qualquer registro único obtido de uma tabela pode ser envolvida em um procedimento para fazê-la funcionar em cada linha de uma tabela, assim:
DROP PROCEDURE IF EXISTS ROWPERROW;
DELIMITER ;;
Então aqui está o procedimento de acordo com o seu exemplo (table_A e table_B usadas para maior clareza)
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;
;;
Então não se esqueça de redefinir o delimitador
DELIMITER ;
E execute o novo procedimento
CALL ROWPERROW();
Você pode fazer o que quiser na linha "INSERT INTO" que eu simplesmente copiei de sua solicitação de exemplo.
Observe CUIDADOSAMENTE que a linha "INSERT INTO" usada aqui reflete a linha da pergunta. De acordo com os comentários a esta resposta, você precisa garantir que sua consulta esteja sintaticamente correta para qualquer versão do SQL que você esteja executando.
No caso simples em que seu campo de ID é incrementado e começa em 1, a linha no exemplo pode se tornar:
INSERT INTO table_B(ID, VAL) VALUES(ID, VAL) FROM table_A WHERE ID=i;
Substituindo a linha "SELECT COUNT" por
SET n=10;
Permitirá que você teste sua consulta nos primeiros 10 registros da tabela_A apenas.
Uma última coisa. Esse processo também é muito fácil de aninhar em tabelas diferentes e foi a única maneira de realizar um processo em uma tabela que inseriu dinamicamente diferentes números de registros em uma nova tabela a partir de cada linha de uma tabela pai.
Se você precisa que ele seja executado mais rápido, tente torná-lo baseado em conjuntos; Você também pode reescrever o texto acima na forma de cursor, mas pode não melhorar o desempenho. por exemplo:
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;
;;
Lembre-se de declarar as variáveis que você usará como sendo do mesmo tipo das tabelas consultadas.
Meu conselho é ir com consultas baseadas em conjunto quando você puder, e usar apenas loops ou cursores simples se for necessário.