How can I loop through all rows of a table? (MySQL)

后端 未结 5 991
情深已故
情深已故 2020-11-27 10:56

I have a table A and there is one primary key ID.

Now I want to go through all rows in A.

I found something like \'for each record in A\', but this seems to

相关标签:
5条回答
  • 2020-11-27 11:33

    You should really use a set based solution involving two queries (basic insert):

    INSERT INTO TableB (Id2Column, Column33, Column44)
    SELECT id, column1, column2 FROM TableA
    
    UPDATE TableA SET column1 = column2 * column3
    

    And for your transform:

    INSERT INTO TableB (Id2Column, Column33, Column44)
    SELECT 
        id, 
        column1 * column4 * 100, 
        (column2 / column12) 
    FROM TableA
    
    UPDATE TableA SET column1 = column2 * column3
    

    Now if your transform is more complicated than that and involved multiple tables, post another question with the details.

    0 讨论(0)
  • 2020-11-27 11:35
        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
        }   
    
    0 讨论(0)
  • 2020-11-27 11:37

    CURSORS are an option here, but generally frowned upon as they often do not make best use of the query engine. Consider investigating 'SET Based Queries' to see if you can achieve what it is you want to do without using a CURSOR.

    0 讨论(0)
  • 2020-11-27 11:47

    Mr Purple's example I used in mysql trigger like that,

    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
    
    0 讨论(0)
  • 2020-11-27 11:55

    Since the suggestion of a loop implies the request for a procedure type solution. Here is mine.

    Any query which works on any single record taken from a table can be wrapped in a procedure to make it run through each row of a table like so:

    DROP PROCEDURE IF EXISTS ROWPERROW;
    DELIMITER ;;
    

    Then here's the procedure as per your example (table_A and table_B used for clarity)

    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;
    ;;
    

    Then dont forget to reset the delimiter

    DELIMITER ;
    

    And run the new procedure

    CALL ROWPERROW();
    

    You can do whatever you like at the "INSERT INTO" line which I simply copied from your example request.

    Note CAREFULLY that the "INSERT INTO" line used here mirrors the line in the question. As per the comments to this answer you need to ensure that your query is syntactically correct for which ever version of SQL you are running.

    In the simple case where your ID field is incremented and starts at 1 the line in the example could become:

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

    Replacing the "SELECT COUNT" line with

    SET n=10;
    

    Will let you test your query on the first 10 record in table_A only.

    One last thing. This process is also very easy to nest across different tables and was the only way I could carry out a process on one table which dynamically inserted different numbers of records into a new table from each row of a parent table.

    If you need it to run faster then sure try to make it set based, if not then this is fine. You could also rewrite the above in cursor form but it may not improve performance. eg:

    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;
    ;;
    

    Remember to declare the variables you will use as the same type as those from the queried tables.

    My advise is to go with setbased queries when you can, and only use simple loops or cursors if you have to.

    0 讨论(0)
提交回复
热议问题