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 :

Erreur sur variable à l'exécution d'une procédure


Sujet :

SQL Procédural MySQL

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    5
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2003
    Messages : 5
    Points : 7
    Points
    7
    Par défaut Erreur sur variable à l'exécution d'une procédure
    Bonjour à tous,

    Ça fait très longtemps que je n'ai pas fait de PL-SQL et c'est la 1ère fois sous MySQL, j'avoue être plus que rouillé ...

    Bref,
    J'ai voulu créer une procédure me permettant de voir la fiabilité des données que l'on doit importer notamment en obtenant le pourcentage de champ vide.

    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
    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
    DELIMITER |
    CREATE PROCEDURE `proc_champ_NULL` (IN `vi_nomtable` VARCHAR(30) charset utf8)
    BEGIN
     
    DECLARE `v_finished` INT DEFAULT 0;
    DECLARE `c_nomcol` VARCHAR(40);
    DECLARE `v_nbligne` INT DEFAULT 0;
    DECLARE `v_result` INT DEFAULT 0;
    DECLARE `v_dt_chargement` DATE;
    DECLARE done INT DEFAULT 0;
     
    DECLARE `cur_nom_table` CURSOR FOR 
    	SELECT `column_name` FROM information_schema.columns WHERE table_name =  `vi_nomtable`;
     
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
    		SELECT '1';
     
    SELECT CURRENT_TIMESTAMP INTO `v_dt_chargement`;
    		SELECT '2';
     
    CREATE TABLE IF NOT EXISTS `stat_champ_NULL`
    	(
    	`nom_table` VARCHAR(30) NULL,
    	`nom_col` VARCHAR(40) NULL,
    	`taux_NULL` VARCHAR(4) NULL,
    	`nb_ligne_total` VARCHAR(4) NULL,
    	`dt_chargement` DATE NULL
    	)
    	ENGINE = InnoDB;
    		SELECT '3';
     
    OPEN `cur_nom_table`;
    		SELECT '4';
     
     
    SELECT COUNT(*) INTO `v_nbligne` FROM `vi_nomtable`;
    		SELECT '5';
     
    REPEAT
     
    FETCH `cur_nom_table` INTO `c_nomcol`;
    		SELECT '6';
     
    SELECT SUM(CASE WHEN `c_nomcol`='' THEN 1 ELSE 0 END)*100/`v_nbligne`
    			INTO `v_result`
    			FROM `vi_nomtable`;
    		SELECT '7';
     
    INSERT INTO `stat_champ_NULL` 
    			VALUES (
    					`vi_nomtable`,
    					`c_nomcol`,
    					`v_result`,
    					`v_nbligne`,
    					`v_dt_chargement`
    					)
    ;
    		SELECT '8';
     
    UNTIL done END REPEAT;
     
    CLOSE `cur_nom_table`;
    		SELECT '9';
     
    END|
    DELIMITER ;

    Et quand je l'execute,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CALL proc_champ_null('import_ldapuser');
    voici ce que j'ai en retour :
    Error Code: 1146 Table 'dbappstore.vi_nomtable' doesn't exist
    J'ai mis des "select +num" un peu partout pour savoir ou ça plante.
    (J'ai pas trouvé d'autre méthode pour m'aider au débugage)
    C'est ligne 36 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT COUNT(*) INTO `v_nbligne` FROM `vi_nomtable`;
    Visiblement il prend pour valeur le nom de la variable "vi_nomtable" et non sa valeur.

    J'ai essayé quantité de solution sans succès ...

    Donc c'est ici, l’âme en peine que j’espère trouver un peu de réconfort.
    Merci pour toute l'aide que vous pourrez m'apporter.
    (ou bien même un peu de réconfort )

  2. #2
    Candidat au Club
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Novembre 2013
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Distribution

    Informations forums :
    Inscription : Novembre 2013
    Messages : 3
    Points : 4
    Points
    4
    Par défaut j'ai la même question
    Bonjour, j'ai la même question, accompagnée d'un exemple un peu plus court
    (peut-être que ça entrainera plus de réponse ....)

    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
     
    CREATE DEFINER=`root`@`localhost` PROCEDURE `CreaTableImportTmp`(IN iNbCol INT)
    BEGIN
    declare CountCol integer default 1;
    declare NomCol varchar(10) DEFAULT '';
     
    drop table if exists `test`.`tblTmpImportCsv` ;
    CREATE TABLE `tblTmpImportCsv` 
    (Col1 varchar(1000));
     
      WHILE CountCol < iNbCol  DO 
     	set CountCol = CountCol + 1;
     	set NomCol = concat('Col', CountCol);
       	Alter Table `test`.`tblTmpImportCsv` ADD NomCol varchar(300);
      END WHILE;
    END;
    Et, en effet, le NomCol de la ligne 14 est considérer comme une chaine et pas comme une variable ... why
    Si kelk1 (ou un autre à la réponse) ...

  3. #3
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 413
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 413
    Points : 1 993
    Points
    1 993
    Par défaut
    Bonjour,

    parce qu'il peut pas faire la différence entre un nom littéral et la variable.

    Pour du DDL, il me semble qu'il préférable d'utiliser EXECUTE .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SET ddl = CONCAT('ALTER TABLE `test`.`tblTmpImportCsv` ADD ', NomCol, '  varchar(300)')
    PREPARE stmt FROM ddl;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    Bien le bonjour chez vous
    Jowo

  4. #4
    Candidat au Club
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Novembre 2013
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Distribution

    Informations forums :
    Inscription : Novembre 2013
    Messages : 3
    Points : 4
    Points
    4
    Par défaut c'est ok ... je vais tacher de creuser
    Merci jowo,

    Tu m'a fait découvrir les requete préparée Execute et ça ma bien comme ça.
    Il me reste à comprendre :
    1) pourquoi j'ai du préfixer la variable avec @ (ça ne marchait pas tel que tu me le proposais)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    		SET @ddl = CONCAT('ALTER TABLE `test`.`tblTmpImportCsv` ADD ', NomCol, '  varchar(300)') ;
    		PREPARE stmt FROM @ddl;
    2) pourquoi je n'arrive pas à utiliser le vrai coté dynamique des requêtes préparée (préparer une seul fois avant la boucle pour ne faire que l'appel à chaque changement de valeur de la variable)
    J'essaye ça mais ça ne marche pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     	PREPARE stmt from 'Alter Table `test`.`tblTmpImportCsv` ADD ? varchar(300) ; ';
    	WHILE CountCol < iNbCol  DO 
    		set CountCol = CountCol + 1;
    		set @NomCol = concat('Col', CountCol);
     	 	Execute stmt using @NomCol ;
    	END WHILE;
     	DEALLOCATE PREPARE stmt;
    Si je trouve (avant que qq'un ne m'explique) je posterai là l'explication

    A+

  5. #5
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 413
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 413
    Points : 1 993
    Points
    1 993
    Par défaut
    Bonjour

    Ton code 2) ne peut pas fonctionner. Les variables ne peuvent être utilisées que pour des valeurs dans une condition ou comme paramètre d'une fonction ou d'une procédure.

    Comme : col1 like ?

    Dans ton cas, il faut passer un "texte complet" à prepare pour l'exécuter.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    	WHILE CountCol < iNbCol  DO 
                    SET @ddlStmt = CONCAT('Alter Table `test`.`tblTmpImportCsv` ADD `Col', CountCol, '` varchar(300) ;';
                    PREPARE stmt FROM @ddlStmt ;
     	 	Execute stmt;
            	DEALLOCATE PREPARE stmt;
    		SET CountCol = CountCol + 1;
    	END WHILE;
    On pourrait être plus efficace en ajoutant toutes les colonnes en une seule passe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    ALTER Table `test`.`tblTmpImportCsv`
        ADD `Col1` varchar(300),
        ADD `Col2` varchar(300),
        ADD `Col3` varchar(300),
        ADD `Col4` varchar(300);
    Bien le bonjour chez vous
    Jowo

  6. #6
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Citation Envoyé par Gambol Voir le message
    2) pourquoi je n'arrive pas à utiliser le vrai coté dynamique des requêtes préparée (préparer une seul fois avant la boucle pour ne faire que l'appel à chaque changement de valeur de la variable)
    J'essaye ça mais ça ne marche pas
    Un ALTER table est une requête de type DDL (data definition langage)
    Celles-ci ne peuvent être utiliser dans une requete sql dynamique.
    Tu auras donc le même rendu avec des requete qui commencent par : create, drop, truncate, ...

    Les requete de type DML (data manipulation langage) peuvent, elles, être utilisées dynamiquement.
    Ceci concerne les clause : SELECT , UPDATE, INSERT , DELETE, MERGE, ..


    Dans une appli logiquement, on n'utilise jamais des requetes de type DDL.
    C'est souvent signe d'une mauvaise modélisation, si l'on doit les utiliser.

    Il reste cependant certain cas exceptionnel, où l'utilisation d'une table temporaire peut être utiliser, comme dans le cas de certain traitement batch.

  7. #7
    Candidat au Club
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Novembre 2013
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Distribution

    Informations forums :
    Inscription : Novembre 2013
    Messages : 3
    Points : 4
    Points
    4
    Par défaut Merci pour vos explications
    Bonjour,

    Merci à tous les 2 pour ces explications détaillées.

    - Jowo, j'ai suivi le conseil et ma boucle ne prépare plus que la requete, qui est executée en une seule passe à la sortie.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    	set @ddl = 'CREATE TABLE `tblTmpImportCsv` (' ; 
    	WHILE CountCol < iNbCol  DO 
    		set @ddl = concat(@ddl, 'Col', CountCol, ' varchar(300), ');
    		set CountCol = CountCol + 1;
    	END WHILE;
    	set @ddl = concat(@ddl, 'Col', CountCol, ' varchar(300)) ');
     
    	PREPARE stmt from @ddl;
    	EXECUTE stmt ;
    	DEALLOCATE PREPARE stmt;
    - Punkoff, j'ai bien noté qu'une bonne modélisation n'a pas besoin d'être changée dynamiquement. En l’occurrence, il ne s'agit pas vraiment d'une appli, je me fait juste une petite proc stock réutilisable car j'ai souvent besoin de charger en base des fichiers plats volumineux de tout genre.
    (il me reste à broder un peu pour ajouter le "load data infile", qq paramêtres, etc)

    Merci

Discussions similaires

  1. Erreur lors de l'exécution d'une procédure stockée
    Par sab_info dans le forum Développement
    Réponses: 7
    Dernier message: 15/03/2013, 17h27
  2. [XL-2003] Erreur lors de l'exécution d'une procédure
    Par pacocnec dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 29/06/2009, 13h39
  3. Erreurs lors de l'exécution d'une procédure
    Par vanesa dans le forum PL/SQL
    Réponses: 2
    Dernier message: 05/01/2009, 18h48
  4. Erreur d'Exécution d'une procédure stockée
    Par h.Madjid dans le forum SQL
    Réponses: 1
    Dernier message: 05/09/2007, 20h34
  5. Réponses: 1
    Dernier message: 15/09/2006, 15h04

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