MySQL存储过程,处理多个游标和查询结果
如何在同一个例程中使用两个游标?如果我删除第二个游标声明并获取循环,则一切正常。该例程用于在我的网络应用程序中添加朋友。它获取当前用户的 id 和我们要添加为好友的好友的电子邮件,然后检查该电子邮件是否具有相应的用户 id,如果不存在好友关系,则会创建一个。除了这个之外,任何其他常规解决方案也都很棒。
DROP PROCEDURE IF EXISTS addNewFriend;
DELIMITER //
CREATE PROCEDURE addNewFriend(IN inUserId INT UNSIGNED, IN inFriendEmail VARCHAR(80))
BEGIN
DECLARE tempFriendId INT UNSIGNED DEFAULT 0;
DECLARE tempId INT UNSIGNED DEFAULT 0;
DECLARE done INT DEFAULT 0;
DECLARE cur CURSOR FOR
SELECT id FROM users WHERE email = inFriendEmail;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
REPEAT
FETCH cur INTO tempFriendId;
UNTIL done = 1 END REPEAT;
CLOSE cur;
DECLARE cur CURSOR FOR
SELECT user_id FROM users_friends WHERE user_id = tempFriendId OR friend_id = tempFriendId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
REPEAT
FETCH cur INTO tempId;
UNTIL done = 1 END REPEAT;
CLOSE cur;
IF tempFriendId != 0 AND tempId != 0 THEN
INSERT INTO users_friends (user_id, friend_id) VALUES(inUserId, tempFriendId);
END IF;
SELECT tempFriendId as friendId;
END //
DELIMITER ;
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 webapp. It takes the id of the current user and the email of the friend we want to add as a friend, then it checks if the email has a corresponding user id and if no friend relation exists it will create one. Any other routine solution than this one would be great as well.
DROP PROCEDURE IF EXISTS addNewFriend;
DELIMITER //
CREATE PROCEDURE addNewFriend(IN inUserId INT UNSIGNED, IN inFriendEmail VARCHAR(80))
BEGIN
DECLARE tempFriendId INT UNSIGNED DEFAULT 0;
DECLARE tempId INT UNSIGNED DEFAULT 0;
DECLARE done INT DEFAULT 0;
DECLARE cur CURSOR FOR
SELECT id FROM users WHERE email = inFriendEmail;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
REPEAT
FETCH cur INTO tempFriendId;
UNTIL done = 1 END REPEAT;
CLOSE cur;
DECLARE cur CURSOR FOR
SELECT user_id FROM users_friends WHERE user_id = tempFriendId OR friend_id = tempFriendId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
REPEAT
FETCH cur INTO tempId;
UNTIL done = 1 END REPEAT;
CLOSE cur;
IF tempFriendId != 0 AND tempId != 0 THEN
INSERT INTO users_friends (user_id, friend_id) VALUES(inUserId, tempFriendId);
END IF;
SELECT tempFriendId as friendId;
END //
DELIMITER ;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
以下是如何在同一例程中使用两个游标的简单示例:
Here is a simple example of how to use two cursors in the same routine:
我知道您找到了更好的解决方案,但我相信您原来问题的答案是您需要 SET Done=0;位于两个游标之间,否则由于前一个处理程序的 Done=1,第二个游标在退出循环之前将仅获取一条记录。
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.
我终于写了一个不同的函数来做同样的事情:
我希望这是一个更好的解决方案,无论如何它工作得很好。感谢您告诉我在不必要时不要使用光标。
I have finally written a different function that does the same thing:
I hope this is a better solution, it works fine anyway. Thanks for telling me not to use cursors when not necessary.
哇,我不知道该说什么,请去阅读并学习一点 SQL,无意冒犯,但这是我见过的最糟糕的 SQL 之一。
SQL 是一种基于集合的语言,游标一般来说很糟糕,在某些情况下它们很有用,但相当罕见。您在这里使用光标是完全不合适的。
第二个光标中的逻辑也有缺陷,因为它将选择包含朋友的任何记录,而不仅仅是所需的友谊。
如果您想修复它,您可以尝试为第二个光标指定不同的名称,但最好重新开始。
对 users_friends 设置复合 PK 或唯一约束,那么您就不必担心检查关系,然后尝试这样的事情。
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.
您可以在 WHERE 子句中使用 EXISTS 子句,而不是使用游标来检查记录是否存在:
在阅读 Paul 关于第二个查询的注释后,我进行了更改,并反转了逻辑,以便插入不会添加重复项。理想情况下,这应该作为复合键(包括两个或更多列)的主键来处理,这将不再需要签入代码。
Rather than using cursors to check for the existence of records, you can use the EXISTS clause in the WHERE clause:
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.