10
votes

MySQL Procédure stockée, manipulation de plusieurs curseurs et résultats de la requête

Comment puis-je utiliser deux curseurs dans la même routine? Si je retire la deuxième déclaration du curseur et que la boucle de récupération, tout va bien fonctionne bien. La routine est utilisée pour ajouter un ami dans mon webApp. Il prend l'identifiant de l'utilisateur actuel et l'email de l'ami que nous souhaitons ajouter un ami, puis il vérifie si l'e-mail ait un identifiant utilisateur correspondant et si aucun lien d'amis n'existe, il en créera une. Toute autre solution de routine que celle-ci serait super également.

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 ;


0 commentaires

5 Réponses :


0
votes

WOW, je ne sais pas quoi dire, s'il vous plaît aller et apprendre un peu SQL un peu, aucune infraction, mais c'est parmi les pires SQL que j'ai jamais semblé.

SQL est une langue reposante, des curseurs, en général, sont mauvaises, il existe des situations quand elles sont utiles, mais elles sont assez rares. Votre utilisation de curseurs ici est totalement inappropriée.

Votre logique dans le deuxième curseur est également défectueuse car elle sélectionnera n'importe quel enregistrement qui empêche l'amitié, non seulement l'amitié requise.

Si vous vouliez résoudre ce problème, vous pouvez essayer de donner Le second curseur d'un nom différant, mais de préférence recommencer.

Définissez un composé pk ou une contrainte unique sur les utilisateurs_friends, alors vous n'avez pas à vous soucier de rechercher une relation, puis essayez quelque chose comme ça. < / p> xxx


2 commentaires

Merci de vos instructions, je suis de nouvelles procédures stockées et j'ai essayé d'utiliser une rutine précédente que j'ai de l'aide ( Stackoverflow.com/questions/1903189/... ), je vais essayer de trouver Différent Apriach à écrire cette procédure.


Et oui, vous avez raison sur la logique, devrait être: Sélectionnez user_id à partir de users_friends où (user_id = tempodridid ​​et ami_id = inuserid) ou (ami_id = tempodridid ​​et user_id = inuserid); Mais comme je l'ai dit, je vais essayer une autre façon de le faire.



1
votes

Plutôt que d'utiliser des curseurs pour rechercher l'existence d'enregistrements, vous pouvez utiliser la clause existante dans la clause 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);


0 commentaires

3
votes

J'ai enfin écrit une fonction différente qui fait la même chose:

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 ;


0 commentaires

4
votes

Je sais que vous avez trouvé une meilleure solution, mais je pense que la réponse à votre question initiale est que vous devez définir effectué = 0; Entre les deux curseurs, sinon le deuxième curseur ne cherchera qu'un seul enregistrement avant de quitter la boucle due à celui de Done = 1 du gestionnaire précédent.


1 commentaires

Oui, je peux voir cela maintenant, tu as raison. Je pense que j'ai fini par résoudre cela de manière meilleure sans curseurs ni boucles.



18
votes

Voici un exemple simple de la manière d'utiliser deux curseurs dans la même routine: xxx


0 commentaires