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 :

PREPARE dans une proc stock


Sujet :

SQL Procédural MySQL

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3
    Par défaut PREPARE dans une proc stock
    Bonjour à tous.
    Je me permets de faire un peu de nécromancie de topic dans la mesure où ce sujet correspond tout à fait à ce que j'essaie de faire.

    Petite présentation du contexte tout d'abord :
    J'ai besoin de faire des requêtes avec un nom de table variable dans une procédure stockée en mysql. Après quelques recherches sur le web, il apparait que pour ce faire, je dois utiliser un PREPARE statement.

    Courageux et optimiste, je me lance. Oui mais voilà, je récupère une erreur :
    "#1312 - PROCEDURE 3620t01.maProcedure can't return a result set in the given context"
    Damn..

    Après pas mal de recherches cette fois-ci, je retiens que :
    -Il n'est pas possible de faire d'utiliser un PREPARE statement dans une fonction ou une procédure stockée SAUF pour les procédures stockées justement DEPUIS la version 5.0.13 de mysql.
    Or, je travaille sur la version 5.0.51.

    Du coup je ne vois vraiment pas d'où peut venir le soucis.
    Si une bonne âme avait une idée..

    Pour info, je mets ici la procédure de test que j'ai faite, basée sur celle utilisée plus haut dans ce topic :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    delimiter |
    CREATE PROCEDURE maProcedure()
    BEGIN
    SET @sqlCMD =  CONCAT('select * from ', 'tickets_J');
    PREPARE stmt FROM @sqlCMD;
    EXECUTE stmt ;
    END
    et l'erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #1312 - PROCEDURE 3620t01.maProcedure can't return a result set in the given context
    Ps : Je précise; si besoin est, que j'ai l'erreur sur le CALL de ma procédure stockée, et pas à la création

    Merci d'avance.

    Thomas

  2. #2
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 291
    Par défaut
    Les procédures stockées de MySQL ne sont pas faites pour envoyer un jeu de résultat... sur des cas simples, ça marche quand même, mais comme elles ne sont pas faites pour ça, ça plante à la moindre petite complexité...

    Le contournement habituel est de faire un CREATE SELECT :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    delimiter |
    CREATE PROCEDURE maProcedure()
    BEGIN
    SET @sqlCMD =  CONCAT('create table tmp_resu select * from ', 'tickets_J');
    PREPARE stmt FROM @sqlCMD;
    EXECUTE stmt ;
    END |
     
    delimiter ;
     
    select * from tmp_resu ;

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3
    Par défaut
    Ok, merci beaucoup, c'est bon à savoir.

    Mais du coup mon problème réel persiste. Je m'explique :
    Le code avec la requete SELECT n'était qu'un test pour tester les PEPARE statement, ce que je cherche en réalité à faire est un INSERT, comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    delimiter |
    CREATE PROCEDURE maProcedure(maTable)
    BEGIN
    SET @sqlCMD =  CONCAT("INSERT INTO ",maTable," VALUES('valeur1','valeur2')");
    PREPARE stmt FROM @sqlCMD;
    EXECUTE stmt ;
    END |
    Du coup à priori il n'y a pas de jeu de résultat renvoyé.
    Mais j'ai tout de même l'erreur.
    Qu'est-ce que j'ai manqué ?

    Merci d'avance,
    Thomas

  4. #4
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 291
    Par défaut
    ça marche chez moi, à condition de corriger ta syntaxe pour avoir un CREATE qui fonctionne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    delimiter |
    CREATE PROCEDURE maProcedure(IN maTable VARCHAR(30))
    BEGIN
    SET @sqlCMD =  CONCAT('INSERT INTO ', maTable, ' VALUES(''valeur1'', ''valeur2'')');
    PREPARE stmt FROM @sqlCMD;
    EXECUTE stmt ;
    END |
    
    delimiter ;
    Vérification :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    create table test(a varchar(50), b varchar(50)) ;
    call maprocedure 'test' ;
    select * from test ;
     
    +---------+---------+
    | a       | b       |
    +---------+---------+
    | valeur1 | valeur2 |
    +---------+---------+
    1 row in set (0.04 sec)

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3
    Par défaut
    Damn, ça ne fonctionne pas chez moi, même une fois le code corrigé..
    Aurais-tu une idée de la cause du problème ?
    Y a-t-il une solution de contournement ?

    Merci d'avance,
    Thomas

  6. #6
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 291
    Par défaut
    Peux-tu dire exactement ce qui ne marche pas (compilation, exécution) et nous donner le
    message d'erreur ?

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 12
    Par défaut


    Merci Antoun pour ton information.

    Je cherchais à réaliser un PREPARE dans une procédure stockée.
    Mon erreur venait du jeu de résultat retourné dans mon SELECT.


    Ton code ===>

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    delimiter |
    CREATE PROCEDURE maProcedure()
    BEGIN
    SET @sqlCMD =  CONCAT('create table tmp_resu select * from ', 'tickets_J');
    PREPARE stmt FROM @sqlCMD;
    EXECUTE stmt ;
    END |
     
    delimiter ;
     
    SELECT * FROM tmp_resu ;
    ===> Marche parfaitement... De plus je rajoute cette astuce de codage dans ma production actuelle.


    Un grand M.E.R.C.I.

    Jérôme.


  8. #8
    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
    Les procédure stockée PEUVENT retourner directement autan de résultats que tu veux, il suffit d'avoir un client mysql avec la bonne version ou d'utiliser un connecteur qui DOIT permettre d'exécuter des requêtes avec un set de résultats multiples...

    La seule limite avec les PREPARE c'est la récursivité avec le même nom de statement stockant l'action à faire et tout ce qui est interdit de toute manière dans les requêtes préparée (comme USE par exemple)

    moi ce code passe très bien et regarde il est un peu complexe... 2 curseurs imbriqué et (oh miracle) un select interne!!!
    Code sql : 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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    -- uniquement pour le test
    drop database if exists hotels;
    create database hotels default character set utf8 collate utf8_general_ci;
    -- on sélectionne la bd quoi qu'il arrive pour bien travailler avec elle par défaut
    use hotels; -- à toi d'adapter
     
    -- on définit les table et on les remplit uniquement pour le test
    create table hotel(
    	id		int(4) not null auto_increment,
    	nom	varchar(255) not null,
    	constraint pk_hotel primary key(id)
    )engine=myisam auto_increment=1;
    create table personne(
    	id		int(4) not null auto_increment,
    	nom	varchar(255) not null,
    	constraint pk_personne primary key(id)
    )engine=myisam auto_increment=1;
    -- la table de liaison, je ne mets pas de contrainte dessus car je la crée avec le moteur myisam qui ne s'en occupe pas
    create table personne_a_dormi(
    	id				int(4) not null auto_increment,
    	idPersonne 	int(4) not null,
    	idHotel		int(4) not null,
    	constraint pk_personne_a_dormi primary key(id)
    )engine=myisam auto_increment=1;
     
    insert into hotel(nom)values("hotel1"),("hotel2"),("hotel3");
    insert into personne(nom)values("personne1"),("personne2"),("personne3"),("personne4");
    insert into personne_a_dormi(idPersonne,idHotel)values(1,1),(1,2),(2,2),(3,1),(3,3),(4,1),(4,2),(4,3);
     
    -- on définit la procédure stockée
    drop procedure if exists recapitulatif;
    delimiter |
    create procedure recapitulatif()
    begin
    	declare ligne text default "personne";
    	declare tmp varchar(255);
    	declare done,test bool;
    	declare cpers,chotel int(4);
    	declare colonnes cursor for select nom from hotel;
    	declare lignes cursor for select id,nom from personne;
    	declare lithotel cursor for select id from hotel;
    	declare CONTINUE HANDLER for SQLSTATE '02000' set done = 1;
    	-- on crée l'entête
    	open colonnes;
    	set done=false;
    	repeat
    		fetch colonnes into tmp;
    		if not done then
    			set ligne=concat(ligne,",",tmp);
    		end if;
    	until done end repeat;
    	close colonnes;
    	select ligne as entete;
    	set done=false;
    	open lignes;
    	repeat
    		fetch lignes into cpers,tmp;
    		if not done then
    			set test=done;
    			set ligne=tmp;
    			open lithotel;
    			repeat
    				fetch lithotel into chotel;
    				if not done then
    					select if(count(id)>0,"Oui","Non") into tmp from personne_a_dormi where idPersonne=cpers and idHotel=chotel;
    					set ligne=concat(ligne,",",tmp);
    				end if;
    			until done end repeat;
    			close lithotel;
    			select ligne;
    			set done=test;
    		end if;
    	until done end repeat;
    	close lignes;
    end|
    delimiter ;
    -- fin de la procédure stockée
     
    -- on teste en appelant la procédure
    call recapitulatif();

    Après c'est soit la configuration soit la version de mysql ou du connecteur mysql dans ton langage interrogateur qui est pas à jour

Discussions similaires

  1. Appels de procedures stockées dans une proc stockée ?
    Par Nadaa dans le forum MS SQL Server
    Réponses: 12
    Dernier message: 17/07/2008, 10h32
  2. Faire un simple SELECT dans une Proc. Stock
    Par MaelstroeM dans le forum Oracle
    Réponses: 2
    Dernier message: 29/08/2007, 09h27
  3. Réponses: 3
    Dernier message: 28/08/2007, 15h21
  4. Réponses: 5
    Dernier message: 27/07/2007, 16h21
  5. Réponses: 2
    Dernier message: 12/06/2006, 12h35

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