MySQL stored procedure, handling multiple cursors and query results

前端 未结 5 1368

How can I use two cursors in the same routine? If I remove the second cursor declaration and fetch loop everthing works fine. The routine is used for adding a friend in my webap

相关标签:
5条回答
  • 2021-02-14 08:38

    I know you found a better solution, but I believe the answer to your original question is that you need to SET Done=0; between the two cursors, otherwise the second cursor will only fetch one record before exiting the loop due to Done=1 from the previous handler.

    0 讨论(0)
  • 2021-02-14 08:54

    Wow, i don't know what to say, please go and read about and learn sql a little, no offense but this is amongst the worst SQL i've ever seem.

    SQL is a set based language, cursors, in general, are bad, there are situations when they are usefull, but they are fairly rare. Your use of cursors here is totally inappropriate.

    Your logic in the second cursor is also flawed since it will select any record which inludes the friend, not just the required friendship.

    If you wanted to fix it you could try giving the second cursor a differant name, but preferably start over.

    Set a compound PK or unique constraint on users_friends, then you don't have to worry about checking for a relationship, then try something like this.

    INSERT INTO users_friends 
    SELECT 
        @inUserId, 
        users.user_id
    FROM 
        users
    WHERE
        email = @inFriendEmail
    
    0 讨论(0)
  • 2021-02-14 08:58

    Here is a simple example of how to use two cursors in the same routine:

    DELIMITER $$
    
    CREATE PROCEDURE `books_routine`()
    BEGIN
      DECLARE rowCountDescription INT DEFAULT 0;
      DECLARE rowCountTitle INT DEFAULT 0;
      DECLARE updateDescription CURSOR FOR
        SELECT id FROM books WHERE description IS NULL OR CHAR_LENGTH(description) < 10;
      DECLARE updateTitle CURSOR FOR
        SELECT id FROM books WHERE title IS NULL OR CHAR_LENGTH(title) <= 10;
    
      OPEN updateDescription;
      BEGIN
          DECLARE exit_flag INT DEFAULT 0;
          DECLARE book_id INT(10);
          DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET exit_flag = 1;
    
          updateDescriptionLoop: LOOP
            FETCH updateDescription INTO book_id;
                IF exit_flag THEN LEAVE updateDescriptionLoop; 
                END IF;
                UPDATE books SET description = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' WHERE books.id = book_id;
            SET rowCountDescription = rowCountDescription + 1;
          END LOOP;
      END;
      CLOSE updateDescription;
    
      OPEN updateTitle;
      BEGIN
          DECLARE exit_flag INT DEFAULT 0;
          DECLARE book_id INT(10);
          DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET exit_flag = 1;
    
          updateTitleLoop: LOOP
            FETCH updateTitle INTO book_id;
                IF exit_flag THEN LEAVE updateTitleLoop; 
                END IF;
                UPDATE books SET title = 'Lorem ipsum dolor sit amet' WHERE books.id = book_id;
            SET rowCountTitle = rowCountTitle + 1;
          END LOOP;
      END;
      CLOSE updateTitle;
    
      SELECT 'number of titles updated =', rowCountTitle, 'number of descriptions updated =', rowCountDescription;
    END
    
    0 讨论(0)
  • 2021-02-14 08:59

    I have finally written a different function that does the same thing:

    DROP PROCEDURE IF EXISTS addNewFriend;
    DELIMITER //
    CREATE PROCEDURE addNewFriend(IN inUserId INT UNSIGNED, IN inFriendEmail VARCHAR(80))
    BEGIN
     SET @tempFriendId = (SELECT id FROM users WHERE email = inFriendEmail);
     SET @tempUsersFriendsUserId = (SELECT user_id FROM users_friends WHERE user_id = inUserId AND friend_id = @tempFriendId);
     IF @tempFriendId IS NOT NULL AND @tempUsersFriendsUserId IS NULL THEN
      INSERT INTO users_friends (user_id, friend_id) VALUES(inUserId, @tempFriendId);
     END IF;
     SELECT @tempFriendId as friendId;
    END //
    DELIMITER ;
    

    I hope this is a better solution, it works fine anyway. Thanks for telling me not to use cursors when not necessary.

    0 讨论(0)
  • 2021-02-14 09:03

    Rather than using cursors to check for the existence of records, you can use the EXISTS clause in the WHERE clause:

    INSERT INTO users_friends 
      (user_id, friend_id) 
    VALUES
      (inUserId, tempFriendId)
    WHERE EXISTS(SELECT NULL 
                   FROM users 
                  WHERE email = inFriendEmail)
      AND NOT EXISTS(SELECT NULL 
                       FROM users_friends 
                      WHERE user_id = tempFriendId 
                        AND friend_id = tempFriendId);
    

    I made an alteration after reading Paul's comments about the second query, and reversed the logic so the insert won't add duplicates. Ideally this should be handled as a primary key being a compound key (including two or more columns), which would stop the need for checking in code.

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