J'écris une procédure stockée, qui ouvre un curseur à une table, puis itérale à tous les enregistrements. Dans le processus itérateur, je crée une requête dynamique basée sur les résultats du premier curseur.
J'ai besoin d'ouvrir le curseur sur Dynamic SQL, mais MySQL ne me permet pas de le faire. Selon le Doc officiel de MySQL: aucune idée de la création de curseur pour une requête dynamique? dans mysql? p> p>
7 Réponses :
Créez une autre procédure et écrivez le code de curseur dans cette nouvelle procédure, puis appelez la procédure à partir de laquelle vous souhaitez déclarer un curseur ... P>
Est-ce vraiment la meilleure solution? Si encombrant!
Je vois 2 problèmes possibles dans votre script: p>
1) "Déclarez curseur2 curseur pour la STMT;" doit probablement être déplacé vers le haut de la procédure avec toutes les autres déclarations, avant toutes les déclarations exécutables. P>
2) Les curseurs ne peuvent pas être basés sur SQL dynamique (c'est-à-dire que je ne pense pas que vous puissiez le construire sur une déclaration préparée). Pour contourner cette limitation, vous pouvez déclarer le curseur en fonction de la vue, puis créer la vue avec SQL dynamique avant d'ouvrir le curseur. Le problème avec cette approche est que les points de vue sont publics - la déclaration du curseur doit avoir un nom fixe pour la vue, de sorte que plusieurs utilisateurs simultanés pouvaient voir par inadvertance que d'autres ont défini de manière dynamique. Mon travail est de vérifier l'existence de la vue et de retarder l'exécution de la procédure jusqu'à ce que la vue soit supprimée. Cela signifie que pour être réalisable dans un environnement occupé, vous devez créer la vue, boucler dans le curseur, puis laisser tomber la vue aussi rapidement que possible. Pas techniquement élégant, mais cette approche travaillait dans ma situation de trafic faible et évite les frais généraux des tables temporaires. Sinon, comme d'autres ont suggéré, des tables temporaires sont en sécurité, mais peuvent avoir une incidence sur les performances. P>
L'approche de Karni est moins encombrante. Créez deux ou plusieurs SPS pour satisfaire chaque branche conditionnelle (pour chacune d'une SQL dynamique aurait été requise). Créez un wrapper SP et des appels de ventilateur de ce SP à «BRICKER» SPS. P>
L'alternative qui est l'approche "Vue préparée" nécessite plus de cycles de processeurs et de mémoire et d'espace disque supplémentaire tout en exécutant la procédure. P>
Comme vous ne pouvez pas utiliser les requêtes dynamiques avec le curseur, car vous ne pouvez pas Déclarez le curseur Cursor_Name pour Select_Statement P>
blockQuote>
définir code> avant
déclarer code>. De plus, vous ne pouvez pas utiliser les procédures stockées
appel code> avec
curseur pour code> p>
appel code> n'est pas un select_statement strong>. p>
Vous devez créer 3 procédures au lieu de seulement 1. P>
Écrivez une procédure stockée pour générer des tables temporaires ou des vues pour vos requêtes dynamiques. LI>
Votre procédure actuelle utilisera curseur pour code>
Sélectionnez code>
à partir de code> les tables temporaires. Mais vous devez vous assurer d'exécuter la procédure de tables / vues temporaires d'abord - pour obtenir des résultats mises à jour. Et vous ne pouvez pas
appel code> une procédure avant
déclarer code> le curseur. C'est la raison pour laquelle vous aurez besoin de la troisième étape. LI>
appel code> la procédure générant des tables / vues temporaires et ensuite
appelez code> votre procédure prévue pour calculer les résultats. Vous devriez enfin utiliser cette dernière procédure comme celle qui effectue votre résultat. LI>
ol>
Il n'est pas autorisé à définir un curseur de cur pour préparer_statement, vous devez définir une instruction SQL valide. La bonne nouvelle est que vous pouvez définir le curseur sur une vue pouvant être créée de manière dynamique plus tard. Par exemple ...
DROP PROCEDURE IF EXISTS my_dynamic_proc; DELIMITER // CREATE PROCEDURE my_dynamic_proc(tablename varchar(64), fieldname varchar(64), country VARCHAR(64)) BEGIN DECLARE adr_value varchar(500); DECLARE done BOOLEAN DEFAULT FALSE; -- Cursor definition DECLARE cur1 CURSOR FOR SELECT address FROM tmp_view_address; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; -- Dynamic view definition and creation SET @v = concat('CREATE OR REPLACE VIEW tmp_view_address as SELECT `',fieldname,'` as address FROM ',tablename,' WHERE country_name = "',country,'" group by 1 order by count(1) desc'); PREPARE stm FROM @v; EXECUTE stm; DEALLOCATE PREPARE stm; -- Open cursor OPEN cur1; read_loop: LOOP FETCH cur1 INTO adr_value; IF done THEN LEAVE read_loop; END IF; -- Basic output result SELECT concat("My address is ",adr_value); -- Use every result in a dynamic update SET @u = concat('update ',tablename,' set new_field_address = "',adr_value,'" where country_name = "',country,'" and new_field_address is null'); PREPARE stm FROM @u; EXECUTE stm; DEALLOCATE PREPARE stm; END LOOP; CLOSE cur1; END// DELIMITER ;
Ce fut vraiment un économiseur de vie. Merci beaucoup d'avoir donné à 100% de ce que je cherchais, et cela a travaillé comme un charme sans tracas nulle part! À votre santé! :)
Ce fil m'a beaucoup aidé alors voici ma réponse sur la manière dont vous utilisez des valeurs d'une table pour itérer cela à travers la requête et sur la base de la deuxième table ou de la vue.
Nous pouvons penser à un travail autour de ce cas en utilisant comptez tous les enregistrements qui seront renvoyés par la requête p>
li>
boucle et parcourez chaque enregistrement renvoyé par la requête, car cela utilise la limite. P>
li>
ol> Voir l'exemple ci-dessous: P> stmt code>:
CREATE PROCEDURE `proc_example`(IN p_where text)
BEGIN
DECLARE v_where text default "";
DECLARE v_cont integer default 0;
#build a dynamic where
set v_where = p_where;
#Count query records
set @v_sqlSelect_count = 'select count(*) into @v_total ';
set @v_sqlSelect_count = concat(@v_sqlSelect_count,'from table ');
set @v_sqlSelect_count = concat(@v_sqlSelect_count,'where ');
set @v_sqlSelect_count = concat(@v_sqlSelect_count,v_where);
#Executa query
PREPARE stmt_total FROM @v_sqlSelect_count;
EXECUTE stmt_total;
DEALLOCATE PREPARE stmt_total;
#if exists records
if (@v_total > 0) then
set v_cont = 0;
navRecords:loop
if (v_cont > (@v_total - 1)) then
leave getAgend;
end if;
#build select
set @v_sqlSelect = 'select id,name ';
set @v_sqlSelect = concat(@v_sqlSelect,'into @id,@name ');
set @v_sqlSelect = concat(@v_sqlSelect,'from table ');
set @v_sqlSelect = concat(@v_sqlSelect,'where ');
set @v_sqlSelect = concat(@v_sqlSelect,v_where);
set @v_sqlSelect = concat(@v_sqlSelect,' order by id asc limit ',v_cont,',1');
#Execute query
PREPARE stmt_select FROM @v_sqlSelect;
EXECUTE stmt_select;
DEALLOCATE PREPARE stmt_select;
#Do anything with the data @id, @name
update table1 set desc1 = @name where id1 = @id;
#Next record
set v_cont = v_cont + 1;
end loop navRecords;
end if;
END