Mam tabelę A i jest jeden identyfikator klucza podstawowego.
Teraz chcę przejść przez wszystkie rzędy schematu A.
Znalazłem coś w rodzaju „dla każdego rekordu w A”, ale wydaje się, że nie jest to sposób, w jaki robisz to w MySQL.
Chodzi o każdy wiersz, który chcę wziąć pole i przekształcić je, wstawić do innej tabeli, a następnie zaktualizować niektóre pola wiersza. Mogę umieścić wybraną część i wstawkę w jednym oświadczeniu, ale nie wiem również, jak uzyskać tam aktualizację. Więc chcę zapętlić. I dla praktyki nie chcę używać niczego innego niż MySQL.
edytować
Byłbym wdzięczny za przykład.
I rozwiązanie, którego nie trzeba poddawać zabiegowi.
edytuj 2
dobrze, pomyśl o tym scenariuszu:
Tabela A i B, każda z polami ID i VAL.
Oto pseudokod tego, co chcę zrobić:
for(each row in A as rowA)
{
insert into B(ID, VAL) values(rowA[ID], rowA[VAL]);
}
w zasadzie kopiowanie zawartości A do B za pomocą pętli.
(to jest tylko uproszczony przykład, oczywiście nie użyłbyś do tego pętli).}
Odpowiedzi:
Ponieważ sugestia pętli implikuje żądanie rozwiązania typu procedury. Tu jest moje.
Każde zapytanie, które działa na każdym pojedynczym rekordzie pobranym z tabeli, można opakować w procedurę, aby przeszło przez każdy wiersz tabeli w następujący sposób:
DROP PROCEDURE IF EXISTS ROWPERROW; DELIMITER ;;
Oto procedura jak na twoim przykładzie (tabela_A i tabela_B użyte dla przejrzystości)
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; ;;
Następnie nie zapomnij zresetować ogranicznika
I uruchom nową procedurę
CALL ROWPERROW();
Możesz zrobić, co chcesz, w wierszu „INSERT INTO”, który po prostu skopiowałem z Twojego przykładowego żądania.
Zauważ UWAŻNIE, że użyty tutaj wiersz "INSERT INTO" odzwierciedla wiersz w pytaniu. Zgodnie z komentarzami do tej odpowiedzi, musisz upewnić się, że twoje zapytanie jest poprawne składniowo dla każdej używanej wersji SQL.
W prostym przypadku, gdy pole ID jest zwiększane i zaczyna się od 1, wiersz w przykładzie mógłby wyglądać następująco:
INSERT INTO table_B(ID, VAL) VALUES(ID, VAL) FROM table_A WHERE ID=i;
Zastąpienie wiersza „WYBIERZ LICZNIK” znakiem
SET n=10;
Pozwoli Ci przetestować zapytanie tylko na pierwszych 10 rekordach w tabeli_A.
Ostatnia rzecz. Ten proces jest również bardzo łatwy do zagnieżdżenia w różnych tabelach i był to jedyny sposób, w jaki mogłem przeprowadzić proces na jednej tabeli, który dynamicznie wstawiał różne liczby rekordów do nowej tabeli z każdego wiersza tabeli nadrzędnej.
Jeśli chcesz, aby działał szybciej, spróbuj ustawić go na podstawie zestawu, jeśli nie, to jest w porządku. Możesz również przepisać powyższe w formie kursora, ale może to nie poprawić wydajności. na przykład:
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; ;;
Pamiętaj, aby zadeklarować zmienne, których będziesz używać, jako tego samego typu, co zmienne z odpytywanych tabel.
Radzę korzystać z zapytań opartych na ustawieniach, kiedy tylko możesz, i używać tylko prostych pętli lub kursorów, jeśli musisz.
źródło
LIMIT i,1000;
iset i = i + 1000
;Naprawdę powinieneś używać rozwiązania opartego na zestawie obejmującym dwa zapytania (podstawowa wstawka):
INSERT INTO TableB (Id2Column, Column33, Column44) SELECT id, column1, column2 FROM TableA UPDATE TableA SET column1 = column2 * column3
A dla Twojej transformacji:
INSERT INTO TableB (Id2Column, Column33, Column44) SELECT id, column1 * column4 * 100, (column2 / column12) FROM TableA UPDATE TableA SET column1 = column2 * column3
Teraz, jeśli twoja transformacja jest bardziej skomplikowana i obejmuje wiele tabel, opublikuj kolejne pytanie ze szczegółami.
źródło
KURSORY są tutaj opcją, ale generalnie są źle widziane, ponieważ często nie wykorzystują one najlepiej silnika zapytań. Rozważ zbadanie `` Zapytań opartych na SET '', aby zobaczyć, czy możesz osiągnąć to, co chcesz, bez użycia CURSORA.
źródło
Przykład Mr Purple, którego użyłem w wyzwalaczu mysql w ten sposób,
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
źródło
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 }
źródło