Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie kann ich alle Zeilen einer Tabelle durchlaufen? (MySQL)

Denn der Vorschlag einer Schleife impliziert die Bitte um eine verfahrensartige Lösung. Hier ist meins.

Jede Abfrage, die mit einem einzelnen Datensatz aus einer Tabelle arbeitet, kann in eine Prozedur eingeschlossen werden, damit sie wie folgt durch jede Zeile einer Tabelle läuft:

Löschen Sie zuerst alle vorhandenen Prozeduren mit demselben Namen und ändern Sie das Trennzeichen, damit Ihr SQL nicht versucht, jede Zeile auszuführen, während Sie versuchen, die Prozedur zu schreiben.

DROP PROCEDURE IF EXISTS ROWPERROW;
DELIMITER ;;

Dann ist hier die Vorgehensweise 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

DELIMITER ;

Und führen Sie die neue Prozedur aus

CALL ROWPERROW();

In der "INSERT INTO"-Zeile, die ich einfach aus Ihrer Beispielanfrage kopiert habe, können Sie machen, was Sie wollen.

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 Version von SQL, die Sie ausführen, syntaktisch korrekt ist.

In dem einfachen Fall, in dem Ihr ID-Feld inkrementiert wird und bei 1 beginnt, könnte die Zeile im Beispiel folgendermaßen werden:

INSERT INTO table_B(ID, VAL) VALUES(ID, VAL) FROM table_A WHERE ID=i;

Ersetzen der Zeile „SELECT COUNT“ durch

SET n=10;

Lässt Sie Ihre Abfrage nur auf den ersten 10 Datensätzen in Tabelle_A testen.

Eine letzte Sache. Dieser Prozess lässt sich auch sehr einfach über verschiedene Tabellen hinweg verschachteln und war die einzige Möglichkeit, einen Prozess für eine Tabelle auszuführen, der dynamisch eine unterschiedliche Anzahl von Datensätzen aus jeder Zeile einer übergeordneten Tabelle in eine neue Tabelle einfügt.

Wenn Sie es schneller laufen lassen möchten, versuchen Sie es auf jeden Fall satzbasiert zu machen, wenn nicht, dann ist das in Ordnung. Sie könnten das Obige auch in Cursorform umschreiben, aber es kann die Leistung nicht verbessern. zB:

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 werden, als den gleichen Typ wie die aus den abgefragten Tabellen zu deklarieren.

Mein Rat ist, setbasierte Abfragen zu verwenden, wenn Sie können, und einfache Schleifen oder Cursor nur zu verwenden, wenn Sie müssen.