Comment utiliser les instructions préparées dans les procédures stockées MySQL?

16

J'utilise mysql et je dois en quelque sorte utiliser la colonne curid retournée par l'instruction préparée dans la requête ultérieure. J'utilise des instructions préparées car, comme je l'ai lu, c'est le seul moyen de passer une variable à la clause LIMIT. J'ai cette procédure stockée ici:

DROP PROCEDURE IF EXISTS fixbalance;
CREATE PROCEDURE fixbalance (userid INT)
  BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE balance INT DEFAULT 0;
  DECLARE idcnt INT;

  SET idcnt = (SELECT COALESCE(COUNT(id), 0) 
               FROM coupon_operations 
               WHERE user_id = userid);
  IF idcnt <> 0 THEN
    WHILE i <= idcnt DO
      BEGIN
        SET @iter = i;
        SET @user_id = userid; 
        SET @sql = CONCAT('SELECT id AS curid 
                           FROM coupon_operations 
                           WHERE user_id = ? 
                           ORDER BY id ASC 
                           LIMIT ?, 1');
        PREPARE stmt FROM @sql;
        EXECUTE stmt USING @user_id, @iter;
        DEALLOCATE PREPARE stmt;
        SET balance = balance + (SELECT points 
                                 FROM coupon_operations 
                                 WHERE user_id = @user_id 
                                 AND id = @curid);
        UPDATE coupon_operations SET balance = balance;
        SET i = i + 1;
      END;
    END WHILE;
  END IF;
END;
|

Cela ne fonctionne pas - je ne sais pas comment passer le curé.

donk
la source

Réponses:

10

La solution était de définir la variable dans l'instruction préparée elle-même comme dans:

SET @sql = CONCAT('SET @curid = SELECT id
                                FROM coupon_operations 
                                WHERE user_id = ? 
                                ORDER BY id ASC 
                                LIMIT ?, 1');
donk
la source
1
À quoi sert CONCATle code ci-dessus?
Pacerier
@Pacerier Vous n'avez pas besoin d'utiliser CONCATsauf si vous passez le nom de la table ou quelque chose comme paramètre. ex)CONCAT('select * from ', the_table_name, ' where id>100');
Deckard
9

Je suis content que vous ayez trouvé votre réponse. Une autre solution serait d'utiliser la syntaxe SELECT ... INTO :

SET @sql = CONCAT('SELECT id INTO @curid FROM coupon_operations 
                   WHERE user_id = ? 
                   ORDER BY id ASC 
                   LIMIT ?, 1');
Derek Downey
la source
0

Veuillez essayer ceci. pour résoudre les instructions Concatenate, PREPARE et EXECUTE comme ci-dessous.

CREATE DEFINER=`products`@`localhost` PROCEDURE `generateMeritList`(
   IN `mastercategory_id` INT(11), 
   IN `masterschools_id` INT(11)
 )
 NO SQL
 begin

  declare total int default 0;
  declare conditions varchar(255) default ''; 
  declare finalQuery varchar(60000) default '';

if mastercategory_id > 0 THEN
    SET conditions =  CONCAT(' and app.masterschools_id = ', mastercategory_id);
end if;

SET @finalQuery = CONCAT(
 "SELECT * FROM applications app INNER JOIN masterschools school ON school.id = app.masterschools_id
WHERE 
 (app.status = 'active'", conditions, " LIMIT ",total); 

 PREPARE stmt FROM @finalQuery;
 EXECUTE stmt;
 DEALLOCATE PREPARE stmt;

end
Dinesh Vaitage
la source
Cet exemple particulier est correct mais je déconseillerais de l'utiliser comme modèle général en raison du risque d'injection SQL . Si l'entrée était une chaîne - telle que VARCHAR - au lieu de INT, cela permettrait potentiellement à un attaquant d'injecter du code SQL. Une instruction préparée correctement créée est plus sûre que la concaténation de chaînes avec une entrée externe.
Juanal