IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SQL Procédural MySQL Discussion :

procstock, cursor et more than one row error


Sujet :

SQL Procédural MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Août 2009
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 45
    Par défaut procstock, cursor et more than one row error
    Bonjour à tous,

    j'ai commencé avant hier à regarder les procédures stockées qui ont l'air très pratiques pour des requêtes redondantes comme j'ai besoin d'en faire.

    Pour l'instant je souhaite juste retourner la liste des objets contenus dans l'inventaire d'un joueur. Après il faudrait que la requête me renvoie la liste et la quantité pour chaque objet sachant que chaque objet est unique. Une "pile" de 8 tarte à la crème correspond donc à 8 entrées dans une table énorme.

    La structure:
    TABLE:
    -primary
    -colonne


    PLAYER: // Liste des joueurs
    -kId
    -name

    ENTITY_INVENTORY: // Liste les inventaires présents dans le monde (joueurs, coffres, marchand, etc...)
    -kId
    -playerkId

    INVENTORY_ITEM: // Liste des objets présents dans les inventaires
    -kId
    -itemTypekId
    -inventorykId

    ITEM_TYPE: // liste des types d'objets avec leurs noms
    -kId
    -name



    Bon alors récupérer tout ça dans une requête PHP avec PDO c'est du gâteau, mais avec une procstock je n'y arrive pas alors que j'y suis depuis 2 jours.

    Mon problème est que lorsqu'il n'y a qu'un seul enregistrement dans la table ITEM_LIST ca marche. Quand il y en a deux je reçois une erreur 1172: return more than one row (logique). J'ajoute donc un curseur dans la proc et là catastrophe, le serveur ne réponds pas...

    Je comprends franchement rien à ce qu'il se passe. Voilà ma procstock qui me renvoie bien une valeur si il n'y a qu'un objet dans l'inventaire ou subquery return more than... si il y a plusieurs objets. SQL me parle probablement de subquery car avant de récupérer les itemName je récupère leurs id dans la table inventory_item.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    BEGIN
     
    SELECT it.name
    INTO name
    FROM item_type it
    JOIN inventory_item ii 
    JOIN entity_inventory ei
    JOIN player p
    ON  it.kId = ii.itemTypekId AND ii.inventorykId = ei.kId AND ei.playerkId = p.kId WHERE p.mId = mId;
     
    END

    Maintenant j'ajoute le curseur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    BEGIN
    declare done int DEFAULT 0;
    DECLARE cursor1 CURSOR FOR
    SELECT it.name
    INTO name
    FROM item_type it
    JOIN inventory_item ii 
    JOIN entity_inventory ei
    JOIN player p
    ON  it.kId = ii.itemTypekId AND ii.inventorykId = ei.kId AND ei.playerkId = p.kId WHERE p.mId = mId;
     
     
    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
    OPEN cursor1;
     
    REPEAT
    FETCH cursor1 INTO name;
    IF done = 0 THEN
    SELECT name;
    END IF;
    UNTIL done
    END REPEAT;
    CLOSE cursor1;
     
    END

    J'ai deux paramètres:
    IN: mId (VARCHAR) à la fin du WHERE de la déclaration du curseur
    OUT: name(VARCHAR) dans le REPEAT


    En espérant avoir fourni toutes les infos nécessaires et dans l'attente de vos réponses , bonne journée.
    Prisonier

  2. #2
    Membre Expert
    Avatar de ericd69
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    1 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2011
    Messages : 1 919
    Billets dans le blog
    1
    Par défaut
    salut,

    évite de faire un "on" final, la syntaxe normalisée c'est un "on" par "join" (tu mets la condition de jointure ainsi juste après la déclaration avec "join" à laquelle elle correspond)... idéalement toujours dire le type de jointure (inner/natural/cross/left)... ça évite les mauvaise surprises

    c'est normal, into sert à affecter une valeur dans une variable or les variables sont des types scalaires (tu ne peux pas y loger plusieurs valeurs comme c'est le cas d'une table)... d'où l'erreur que tu obtiens...

    en fait si tu veux lister les items tu n'a pas besoin de ça...

    juste de mettre la requête dans ta procédure avec 1 seul paramètre l'identifiant du joueur (évite de nommer pareil une variable et une colonne)
    et tu traite ta liste derrière coté applicatif...

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    BEGIN
     
    SELECT it.name
    FROM item_type it
    JOIN inventory_item ii 
    JOIN entity_inventory ei
    JOIN player p
    ON  it.kId = ii.itemTypekId AND ii.inventorykId = ei.kId AND ei.playerkId = p.kId WHERE p.mId = mId;
     
    END

    si tu veux le faire dans une autre procédure 2 solutions:
    • une table temporaire (engine=memory, la plus efficace des solutions)
    • une chaine de caractères correspondant à la sérialisation des résultats (par exemple concaténation des résultats avec un séparateur)


    faut que tu sois clair dans l'organisation de tes traitements...

    les procédures stockées vont apporter une meilleure sécurisation et isolation entre application et sgbd et un gain de bande passante...

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Août 2009
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 45
    Par défaut
    Merci pour ta réponse !
    Bon je comprends une partie de ce que tu dis:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    BEGIN
     
    SELECT it.name
    INTO name
    FROM item_type it
    JOIN inventory_item ii 
    ON it.kId = ii.itemTypekId 
    JOIN entity_inventory ei
    ON ii.inventorykId = ei.kId
    JOIN player p
    ON ei.playerkId = p.kId WHERE p.mId = player_mId;
     
    END
    Le problème c'est que je vais avoir une subquery returns more than one row encore vu que j'aurais plusieurs inventory_item.itemTypekId de renvoyés. Du coup il faut que je stock cette liste dans une table temporaire en memory engine c'est ça ?

    Puis ensuite je dois lire cette table temporaire mais je ne comprends pas comment. Le SELECT * va me renvoyer la meme erreur non ?
    Ou alors faire un CONCAT dans la requete ? Mais n'y a t-il pas une autre solution que concat ? Par exemple un VARCHAR ne suffira peut etre pas à renvoyer toutes les données et j'ai peur de partir sur des echanges trop lourds avec le serveur. Je précise que c'est pour un jeu vidéo et que cette fonction sert a mettre à jour l'inventaire du joueur dès qu'il récupère un nouvel objet, et c'est souvent.

    PS: J'ai lu que le cursor était largement déprécié par rapport à la temp_table, qu'en penses tu ?

  4. #4
    Membre Expert
    Avatar de ericd69
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    1 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2011
    Messages : 1 919
    Billets dans le blog
    1
    Par défaut
    alors je pense que tu as un gros problème à élucider: qu'est ce que tu fais de cette liste... qu'est ce qui la traite derrière...

    une variable avec out comme sens ne sert qu'à stocker une valeur UNIQUE !!!

    ensuite le curseur sert à faire un traitement par ligne, la table temporaire sert à stocker temporairement des donner pour des traitements via un autre select ensuite par exemple... c'est pas la même utilisation...

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Août 2009
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 45
    Par défaut
    Alors je vais t'expliquer clairement ou les données vont, le comment c'est une autre histoire !
    Depuis la BDD organisé comme tu la voit, je vais essayer de trouver le bon cheminement:

    creation d'une table temporaire avec pour champs
    item_id|item_type_id

    Ensuite je dois calculer chaque quantité d' item_type_id (COUNT ?)et concaténer (CONCAT ?) le tout pour arriver à un String tel que:

    item_id item quantity|item_id item quantity|etc...

    Ce String est traité en aval en Java pour afficher l'inventaire au joueur.

    -------------------------------------------
    Infos diverses:
    Pour ce qui est du Java, je suis au point. J'arrive à me connecter à la BDD, exécuter une storedproc et récupérer le résultat pour le traiter.

    Pour cette requete je n'ai pas besoin de grand chose de plus mais après je devrais en faire une plus compliquée avec des transactions, j'ai donc vraiment besoin de comprendre le fonctionnement des storedproc pour mener à bien mon projet.

    Merci à toi.

  6. #6
    Membre Expert
    Avatar de ericd69
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    1 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2011
    Messages : 1 919
    Billets dans le blog
    1
    Par défaut
    y a plus simple et efficace... je pense...

    ton connecteur mysql java te permet de faire une boucle de lecture...

    d'où l'intérêt d'un simple select dans la procédure stockée... et directement faire un tableau...

    au lieu de faire différents reader (dont un parseur pour te cracher un tableau)

    faut être le plus simple et efficace pour un jeu surtout s'il est multijoueur et sur le réseau... car tu auras forcément la gestion de lags...

    de toute façon le client ne doit contenir aucun sql vu qu'il peut facilement être désassemblé et seul le serveur doit gérer les échanges avec le sgbd...

    après tu auras un vrai gain de temps d'exécution avec les procédures si tu utilises le principe des jobs (threads permanent ayant une connexion permanent au sgbd à qui ont passe des taches à traiter) car les procédures sont recompilées à chaque premier appel de chaque connexion)

    vois tu l'idée?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 18/09/2013, 09h14
  2. Problème: "Query returns more than one row"
    Par ctobini dans le forum Requêtes
    Réponses: 1
    Dernier message: 27/09/2007, 11h48
  3. Réponses: 4
    Dernier message: 25/01/2007, 15h02
  4. Réponses: 3
    Dernier message: 08/12/2006, 17h28
  5. ORA-01427: single-row subquery returns more than one row
    Par hadid dans le forum Langage SQL
    Réponses: 3
    Dernier message: 31/10/2006, 15h35

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo