Eu tenho uma tabela A e há um ID de chave primária.
Agora quero percorrer todas as linhas em A.
Eu encontrei algo como 'para cada registro em A', mas parece não ser assim que você faz no MySQL.
A questão é que para cada linha eu quero pegar um campo e transformá-lo, inseri-lo em outra tabela e então atualizar alguns dos campos da linha. Posso colocar a parte select e a insert em uma instrução, mas não sei como fazer a atualização lá também. Então, eu quero fazer um loop. E para praticar, não quero usar nada além do MySQL.
editar
Eu apreciaria um exemplo.
E uma solução que não precisa ser colocada em procedimento.
editar 2
ok pense neste cenário:
Tabela A e B, cada um com os campos ID e VAL.
Este é o pseudocódigo para o que desejo fazer:
for(each row in A as rowA)
{
insert into B(ID, VAL) values(rowA[ID], rowA[VAL]);
}
basicamente copiando o conteúdo de A para B usando um loop.
(este é apenas um exemplo simplificado, é claro que você não usaria um loop para isso.)}
Respostas:
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
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.
fonte
LIMIT i,1000;
eset i = i + 1000
;Você realmente deve usar uma solução baseada em conjunto envolvendo duas consultas (inserção básica):
INSERT INTO TableB (Id2Column, Column33, Column44) SELECT id, column1, column2 FROM TableA UPDATE TableA SET column1 = column2 * column3
E para sua transformação:
INSERT INTO TableB (Id2Column, Column33, Column44) SELECT id, column1 * column4 * 100, (column2 / column12) FROM TableA UPDATE TableA SET column1 = column2 * column3
Agora, se sua transformação é mais complicada do que isso e envolve várias tabelas, poste outra pergunta com os detalhes.
fonte
CURSORES são uma opção aqui, mas geralmente desaprovados, pois geralmente não fazem o melhor uso do mecanismo de consulta. Considere investigar 'Consultas baseadas em SET' para ver se você pode alcançar o que deseja sem usar um CURSOR.
fonte
O exemplo do Sr. Purple que usei no gatilho do mysql assim,
begin DECLARE n INT DEFAULT 0; DECLARE i INT DEFAULT 0; Select COUNT(*) from user where deleted_at is null INTO n; SET i=0; WHILE i<n DO INSERT INTO user_notification(notification_id,status,userId)values(new.notification_id,1,(Select userId FROM user LIMIT i,1)) ; SET i = i + 1; END WHILE; end
fonte
Use this: $stmt = $user->runQuery("SELECT * FROM tbl WHERE ID=:id"); $stmt->bindparam(":id",$id); $stmt->execute(); $stmt->bindColumn("a_b",$xx); $stmt->bindColumn("c_d",$yy); while($rows = $stmt->fetch(PDO::FETCH_BOUND)) { //---insert into new tble }
fonte