Ich habe eine Tabelle A und es gibt eine Primärschlüssel-ID.
Jetzt möchte ich alle Zeilen in A durchgehen.
Ich habe so etwas wie "für jeden Datensatz in A" gefunden, aber so scheint es in MySQL nicht zu sein.
Für jede Zeile möchte ich ein Feld nehmen und transformieren, es in eine andere Tabelle einfügen und dann einige Felder der Zeile aktualisieren. Ich kann den ausgewählten Teil und die Einfügung in eine Anweisung einfügen, aber ich weiß auch nicht, wie ich das Update dort einfügen soll. Also möchte ich eine Schleife machen. Und zum Üben möchte ich nichts anderes als MySQL verwenden.
bearbeiten
Ich würde mich über ein Beispiel freuen.
Und eine Lösung, die nicht in ein Verfahren einbezogen werden muss.
bearbeiten 2
Okay, denken Sie an dieses Szenario:
Tabelle A und B mit den Feldern ID und VAL.
Dies ist der Pseudocode für das, was ich tun möchte:
for(each row in A as rowA)
{
insert into B(ID, VAL) values(rowA[ID], rowA[VAL]);
}
Grundsätzlich wird der Inhalt von A mit einer Schleife nach B kopiert.
(Dies ist nur ein vereinfachtes Beispiel, dafür würden Sie natürlich keine Schleife verwenden.)}
Antworten:
Da der Vorschlag einer Schleife die Anforderung einer Lösung vom Prozedurtyp impliziert. Hier ist mein.
Jede Abfrage, die mit einem einzelnen Datensatz aus einer Tabelle funktioniert, kann in eine Prozedur eingeschlossen werden, damit sie wie folgt durch jede Zeile einer Tabelle läuft:
DROP PROCEDURE IF EXISTS ROWPERROW; DELIMITER ;;
Dann ist hier die Prozedur gemäß Ihrem Beispiel (Tabelle_A und Tabelle_B zur Verdeutlichung verwendet)
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; ;;
Vergessen Sie dann nicht, das Trennzeichen zurückzusetzen
Führen Sie die neue Prozedur aus
CALL ROWPERROW();
In der Zeile "INSERT INTO", die ich einfach aus Ihrer Beispielanfrage kopiert habe, können Sie tun, was Sie möchten.
Beachten Sie sorgfältig, dass die hier verwendete Zeile "INSERT INTO" die Zeile in der Frage widerspiegelt. Gemäß den Kommentaren zu dieser Antwort müssen Sie sicherstellen, dass Ihre Abfrage für jede von Ihnen ausgeführte SQL-Version syntaktisch korrekt ist.
In dem einfachen Fall, in dem Ihr ID-Feld inkrementiert ist und bei 1 beginnt, könnte die Zeile im Beispiel wie folgt lauten:
INSERT INTO table_B(ID, VAL) VALUES(ID, VAL) FROM table_A WHERE ID=i;
Ersetzen der Zeile "SELECT COUNT" durch
SET n=10;
Ermöglicht es Ihnen, Ihre Abfrage nur für die ersten 10 Datensätze in table_A zu testen.
Eine letzte Sache. Dieser Prozess ist auch sehr einfach in verschiedene Tabellen zu verschachteln und war die einzige Möglichkeit, einen Prozess für eine Tabelle auszuführen, bei dem aus jeder Zeile einer übergeordneten Tabelle dynamisch unterschiedliche Anzahlen von Datensätzen in eine neue Tabelle eingefügt wurden.
Wenn Sie es benötigen, um schneller zu laufen, versuchen Sie auf jeden Fall, es set-basiert zu machen. Wenn nicht, ist dies in Ordnung. Sie können das Obige auch in Cursorform umschreiben, aber es kann die Leistung nicht verbessern. z.B:
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; ;;
Denken Sie daran, die Variablen, die Sie verwenden, als denselben Typ wie die aus den abgefragten Tabellen zu deklarieren.
Mein Rat ist, mit setbasierten Abfragen zu arbeiten, wenn Sie können, und nur einfache Schleifen oder Cursor zu verwenden, wenn Sie müssen.
quelle
LIMIT i,1000;
undset i = i + 1000
;Sie sollten wirklich eine satzbasierte Lösung verwenden, die zwei Abfragen umfasst (Grundeinfügung):
INSERT INTO TableB (Id2Column, Column33, Column44) SELECT id, column1, column2 FROM TableA UPDATE TableA SET column1 = column2 * column3
Und für deine Transformation:
INSERT INTO TableB (Id2Column, Column33, Column44) SELECT id, column1 * column4 * 100, (column2 / column12) FROM TableA UPDATE TableA SET column1 = column2 * column3
Wenn Ihre Transformation komplizierter ist und mehrere Tabellen umfasst, stellen Sie eine weitere Frage mit den Details.
quelle
CURSOREN sind hier eine Option, werden jedoch im Allgemeinen verpönt, da sie die Abfrage-Engine häufig nicht optimal nutzen. Untersuchen Sie "SET-basierte Abfragen", um festzustellen, ob Sie ohne Verwendung eines CURSOR das erreichen können, was Sie möchten.
quelle
Das Beispiel von Herrn Purple, das ich so in MySQL-Trigger verwendet habe,
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
quelle
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 }
quelle