Car la suggestion d'une boucle implique la demande d'une solution de type procédure. Voici le mien.
Toute requête qui fonctionne sur un seul enregistrement extrait d'une table peut être enveloppée dans une procédure pour la faire parcourir chaque ligne d'une table comme ceci :
Supprimez d'abord toute procédure existante portant le même nom et modifiez le délimiteur afin que votre SQL n'essaie pas d'exécuter chaque ligne pendant que vous essayez d'écrire la procédure.
DROP PROCEDURE IF EXISTS ROWPERROW;
DELIMITER ;;
Ensuite, voici la procédure selon votre exemple (table_A et table_B utilisées pour plus de clarté)
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;
;;
Alors n'oubliez pas de réinitialiser le délimiteur
DELIMITER ;
Et exécutez la nouvelle procédure
CALL ROWPERROW();
Vous pouvez faire ce que vous voulez sur la ligne "INSERT INTO" que j'ai simplement copiée de votre exemple de requête.
Notez ATTENTIVEMENT que la ligne "INSERT INTO" utilisée ici reflète la ligne de la question. Selon les commentaires de cette réponse, vous devez vous assurer que votre requête est syntaxiquement correcte pour la version de SQL que vous utilisez.
Dans le cas simple où votre champ ID est incrémenté et commence à 1, la ligne de l'exemple pourrait devenir :
INSERT INTO table_B(ID, VAL) VALUES(ID, VAL) FROM table_A WHERE ID=i;
Remplacement de la ligne "SELECT COUNT" par
SET n=10;
Vous permettra de tester votre requête sur les 10 premiers enregistrements de la table_A uniquement.
Une dernière chose. Ce processus est également très facile à imbriquer dans différentes tables et était le seul moyen pour moi d'effectuer un processus sur une table qui insérait dynamiquement différents nombres d'enregistrements dans une nouvelle table à partir de chaque ligne d'une table parent.
Si vous avez besoin qu'il s'exécute plus rapidement, essayez de le faire en fonction de l'ensemble, sinon c'est bien. Vous pouvez également réécrire ce qui précède sous forme de curseur, mais cela n'améliorera peut-être pas les performances. ex :
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;
;;
N'oubliez pas de déclarer les variables que vous utiliserez comme étant du même type que celles des tables interrogées.
Mon conseil est d'utiliser des requêtes basées sur des ensembles lorsque vous le pouvez et de n'utiliser que des boucles ou des curseurs simples si vous le devez.