Хранимая процедура MySQL, обрабатывая несколько курсоров и результатов запроса

Как я могу использовать два курсора в той же стандартной программе? Если я удаляю второе объявление курсора и выбираю цикл, все хорошо работает. Стандартная программа используется для добавления друга в моем веб-приложении. Это берет идентификатор текущего пользователя и электронное письмо друга, которого мы хотим добавить как друг, затем это проверяет, имеет ли электронная почта соответствующий идентификатор пользователя и если никакой друг, отношение существует, оно создаст тот. Любое другое стандартное решение, чем этот было бы отличным также.

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 ;
8
задан Jonathan Leffler 3 January 2010 в 15:25
поделиться

4 ответа

[

] Я наконец-то написал другую функцию, которая делает то же самое:[

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

] Надеюсь, это лучшее решение, оно все равно работает хорошо. Спасибо, что сказали мне не использовать курсоры, когда в этом нет необходимости.[

]
2
ответ дан 5 December 2019 в 06:53
поделиться

Вместо того, чтобы использовать курсоры для проверки существования записей, можно воспользоваться пунктом EXISTS в пункте WHERE:

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

Я внес изменения после прочтения комментариев Пола о втором запросе, и изменил логику так, чтобы вставка не добавляла дубликатов. В идеале это должно быть обработано как первичный ключ, являющийся составным ключом (включающим в себя два или более столбцов), что бы остановило необходимость проверки в коде.

1
ответ дан 5 December 2019 в 06:53
поделиться

Вау, я не знаю, что сказать, пожалуйста, пойдите и читайте и читайте и изучите SQL, без обиды, но это среди худшего SQL, который я когда-либо кажутся.

SQL - это установленный на основе языка, курсорами, в целом, плохие, существуют ситуации, когда они полезны, но они довольно редки. Ваше использование курсоров здесь совершенно неуместно.

Ваша логика во втором курсоре также не повреждена, поскольку она выберет любую запись, которая вписывает друга, а не только необходимую дружбу.

Если вы хотите исправить его, вы можете попробовать дать второй курсор разумное имя, но предпочтительно запускаться.

Установите соединение PK или уникальное ограничение на пользователя_Други, то вам не нужно беспокоиться о проверке отношений, то попробуйте что-то вроде этого.

INSERT INTO users_friends 
SELECT 
    @inUserId, 
    users.user_id
FROM 
    users
WHERE
    email = @inFriendEmail
0
ответ дан 5 December 2019 в 06:53
поделиться

Я знаю, что вы нашли лучшее решение, но я считаю, что ответ на ваш исходный вопрос состоит в том, что вам нужно установить SET Done = 0; между двумя курсорами, иначе второй курсор будет извлекать только одну запись перед выходом из цикла из-за Done = 1 из предыдущего обработчика.

4
ответ дан 5 December 2019 в 06:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: