Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème de Trigger

Sujet résolu
    6 novembre 2017 à 15:15:35

    Bonjour à tous,
    Dans le cadre de l'utilisation d'un PIM (Akeneo) je cherche à effectuer un remplissage de champs de manière automatique en fonction du remplissage de certains autres champs. 
    J'ai déjà mis en place un trigger ( BEFORE INSERT) qui permet d'incrémenter automatiquement le sku et qui fonctionne bien: 
    BEGIN
        IF NEW.value_string IS NOT NULL AND NEW.attribute_id=1
        THEN
            SET NEW.value_string = (SELECT max(value_string) from pim_catalog_product_value WHERE attribute_id=1)+1;
            
            END IF;
        
    END
    Dans la suite de mon trigger, à l'insertion d'un nouveau code gtin13 j'aimerai que le champs 'id_regroupement' soit complété avec ce nouveau code GTIN13
    S'il n 'y a pas de code GTIN13 alors je prend le cip13 et si pas de cip13 alors je prends le cip7
    Voici les champs de la base qui sont visés et qui illustrent le cas ou un code GTIN13 existe en base, l'id_regroupement doit alors être égal à ce code GTIN13
    Attribute_id    value_string
    1                    100000100            <--sku
    167      35770570054418   <-- id_regroupement
    154      35770570054418  <-- GTIN13
    157      130000000          <-- cip13
    158      7777777  <-- cip7
    Ci-dessous le pseudo code que j'aimerai mettre en place
    BEGIN
    
    IF NEW.value_string IS NOT NULL AND NEW.attribute_id=154 // Je cible la valeur entrée dans GTIN13
         THEN
         UPDATE la value_string où l'attribute_id est égal à 167 avec la NEW.value_string du GTIN13  
    END IF;
    
    IF NEW.value_string IS NOT NULL AND NEW.attribute_id=157 // Je cible la valeur entrée dans cip13
    	THEN
    	UPDATE la value_string où l'attribute_id est égal à 167 avec la NEW.value_string du cip13
    END IF;
    
    IF NEW.value_string IS NOT NULL AND NEW.attribute_id=158 // Je cible la valeur entrée dans cip7
    	THEN
    	UPDATE la value_string où l'attribute_id est égal à 167 avec la NEW.value_string du cip7
    END IF;
    
    END
    	
    Pour le déclenchement à l'insertion d un GTIN13(attribute_id=154)J'ai essayé, une requete du genre :
    	 IF NEW.value_string IS NOT NULL AND NEW.attribute_id=154
       THEN
       		UPDATE pim_catalog_product_value SET value_string=`NEW.value_string` WHERE attribute_id=167;
    	END IF;
    Le trigger a l'air valide mais lorsque je teste rien ne se passe et j'ai cette erreur dans les logs:
    cant update table 'pim_catalog_product_value' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
    Merci d'avance pour votre aide
    • Partager sur Facebook
    • Partager sur Twitter
      6 novembre 2017 à 15:39:48

      Bonjour,

      Dans un TRIGGER tu ne peux pas modifier la table sur laquelle est posée le TRIGGER, sinon selon déclenche une boucle infinie d'UPDATE ...

      Je suppose que ton TRIGGER est placé BEFORE INSERT ON pim_catalogue_product_value ... Du coup au sein de ce TRIGGER, tu ne peux agir sur cette table ...

      Après je n'ai rien compris à ton sujet car je ne sais pas de quoi l'on parle ici ...

      Pourrais-tu essayer de détailler un peu plus ta question, en nous donnant le code complet de ton TRIGGER (CREATE TRIGGER ...) et un exemple avant/après de ce qui doit être fait par le TRIGGER ?

      • Partager sur Facebook
      • Partager sur Twitter
      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
        6 novembre 2017 à 16:08:04

        Ok je vois ce que tu veux dire et j'ai essayé aussi avec un after insert ça ne change rien.

        Je vais essayer d'être un peu plus clair. J'utilise un PIM (Product Information Manager) qui permet de gérer des produits par une interface graphique. Cette solution s'appuie sur une base mysql en étoile (l'attribute_id permet l'identification du champs Ex: l'attribute_id =1 correspond au sku).

        Pour faciliter la saisie à l'intérieur de ce PIM, je veux que certains champs se remplissent automatiquement et c'est pour cela que je veux mettre en place des triggers qui se déclenchent lorsque certains champs du PIM sont remplis.

        J'ai par exemple 3 types de codes produits: un gtin, un cip7 et un cip13. J'ai un autre champs nommé ID_regroupement. Je veux que ce dernier champs se remplisse automatiquement si un GTIN est saisie, sinon je prends le cip7 sinon je prends le cip13.

        Voila le trigger, j'utilise l'option déclencheur de phpmyadmin avec un moment BEFORE et un évenement INSERT

        BEGIN
            IF NEW.value_string IS NOT NULL AND NEW.attribute_id=1  // Si le champs sku n'est pas null
            THEN
                SET NEW.value_string = (SELECT max(value_string) from pim_catalog_product_value WHERE attribute_id=1)+1; // j'incrémente
                
                END IF;
        

        Pour l'instant je voudrai juste que mon trigger se déclenche à la saisie d'un GTIN (attribute_id=154) et que ca me remplisse le champs 'id_regroupement'

        IF NEW.value_string IS NOT NULL AND NEW.attribute_id=154 // Si le GTIN13 n'est pas null
          	THEN 
            	UPDATE pim_catalog_product_value SET value_string=`NEW.value_string` WHERE attribute_id=167; //mettre à jour le champs id_regroupement(qui correspond à l'attribute_id 167)
            
         	END IF;
        
        END

        -
        Edité par Benzouye 6 novembre 2017 à 16:16:15

        • Partager sur Facebook
        • Partager sur Twitter
          6 novembre 2017 à 16:32:48

          JbLau a écrit:

          j'ai essayé aussi avec un after insert ça ne change rien

          Oui, la logique est exactement la même que ce soit BEFORE ou AFTER, et c'est un comportement normal permettant d'éviter des boucles infinies.

          Par contre je ne comprends toujours pas ce que tu cherches à faire ...

          Je suppose que ton premier bloc IF ... THEN SET ... fonctionne. Par contre ton deuxième bloc IF ne va pas.

          Tu essayes de mettre à jour la table pim_catalog_product_value alors que je suppose que c'est la table sur laquelle est posé le TRIGGER ...

          Avec ton UPDATE tu essayes de mettre à jour value_string pour tous les enregistrements où attribute_id = 167 ... et ça plante ... normal ...

          Je renouvelle mes questions :

          Benzouye a écrit:

          en nous donnant le code complet de ton TRIGGER (CREATE TRIGGER ...) et un exemple avant/après de ce qui doit être fait par le TRIGGER ?

          • Partager sur Facebook
          • Partager sur Twitter
          Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
            6 novembre 2017 à 17:07:06

            Oui mon premier bloc fonctionne bien.

            J'ai bien compris qu'on ne pouvait pas mettre à jour la table sur laquelle est posée le trigger mais alors je vois pas trop comment faire autrement...

            Je n'ai pas de code plus complet à te fournir désolé et je vois pas comment être plus clair que ca:

            Je veux que mon trigger vérifie qu'il y a un code GTIN13 non null et si c'est le cas je veux prendre cette valeur pour l'insérer dans le champs id_regroupement.

            L'algo se présenterait ainsi :

            BEGIN

            Si une nouvelle valeur de GTIN13 est non nulle

             Alors récupère cette nouvelle valeur de GTIN13  et mets à jour le champs id_regroupement (qui par défaut à été crée avec une valeur nulle) avec cette valeur de GTIN13

            END

            Le problème c'est que la base est en étoile, il n'y a pas à proprement dit de colonne GTIN ou Id_regroupement, je dois me baser sur l'attribute_id pour cibler ces champs.

            CREATE DEFINER=`root`@`localhost` TRIGGER `controlePIM` BEFORE INSERT ON `pim_catalog_product_value` FOR EACH ROW
            
            
            BEGIN
            
                IF NEW.value_string IS NOT NULL AND NEW.attribute_id=1
            
                THEN
            
                    SET NEW.value_string = (SELECT max(value_string) from pim_catalog_product_value WHERE attribute_id=1)+1;
            
                    
            
                    END IF;
            
                    
            IF NEW.value_string IS NOT NULL AND NEW.attribute_id=154
            
               THEN
            
               
            
               /*Ici je veux faire un set sur la value_string qui a l'attribute_id=167, que cette valeur soit égale à la NEW.value_string*/
            
               
            
               END IF;
            
            END



            -
            Edité par JbLau 6 novembre 2017 à 17:46:34

            • Partager sur Facebook
            • Partager sur Twitter
              6 novembre 2017 à 17:49:25

              On ne se comprend pas :p

              Benzouye a écrit:

              Avec ton UPDATE tu essayes de mettre à jour value_string pour tous les enregistrements où attribute_id = 167

              Ce n'est pas ce que tu dis vouloir faire :

              JbLau a écrit:

              Je veux que mon trigger vérifie qu'il y a un code GTIN13 non null et si c'est le cas je veux prendre cette valeur pour l'insérer dans le champs id_regroupement.

              Du coup je suis perdu, d'où ma question :

              Benzouye a écrit:

              un exemple avant/après de ce qui doit être fait par le TRIGGER ?

              -
              Edité par Benzouye 6 novembre 2017 à 17:49:44

              • Partager sur Facebook
              • Partager sur Twitter
              Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                6 novembre 2017 à 17:59:19

                Oui je comprends ton incompréhension :(

                En fait ce que je veux dire c'est que je veux mettre à jour la value_string juste de l'enregistrement actuel où l'attribute_id=167. 

                C'est vraiment pas simple à expliquer avec ce style de base..

                En gros chaque fois que je crée 1 produit dans le PIM, ca me crée en base 10 lignes avec un attribute_id respectif pour chacune des lignes ( Chaque ligne correspondant à un caractéristique du produit, un prix, un code etc..)

                Ces 10 lignes ont en commun le même entity_id (1 produit-> 10 lignes avec un attribute_id différent mais avec le même entity_id)

                • Partager sur Facebook
                • Partager sur Twitter
                  6 novembre 2017 à 18:02:49

                  JbLau a écrit:

                  je veux mettre à jour la value_string juste de l'enregistrement actuel où l'attribute_id=167

                  Peux-tu nous donner un exemple de données que tu vas insérer (juste les colonnes impliquées) ?

                  Et ce que tu voudrais obtenir au final après le travail du TRIGGER ?

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                    8 novembre 2017 à 10:19:22

                    Voilà une copie de la base ci-dessous avec des champs déjà complétés.

                    Pour l'exemple considère que je veux mettre à jour la value_string qui a l'attribute_id 169.  Je veux que lorsque un code GTIN13 existe au niveau de l'attribute_id 154 (3577057054418) le trigger complete automatiquement la value _string avec l'attribute_id 169 avec ce code. 

                    • Partager sur Facebook
                    • Partager sur Twitter
                      8 novembre 2017 à 10:41:38

                      Je commence à voir un peu mieux ... même si je ne comprends toujours pas la logique ...

                      Je ne pense pas que tu puisses faire cela avec un TRIGGER ... en tout cas selon mes connaissances de MySQL ...

                      Tu veux modifier un autre enregistrement que celui qui est en train d'être inséré, donc modifier la même table ... ce que MySQL ne t'autorisera jamais car potentiellement boucle infinie ...

                      A mon avis, deux solutions ... soit tu places l'intelligence que tu voulais au TRIGGER dans ton code applicatif (bof bof), soit tu passes par une procédure stockée MySQL ...

                      Dans ton code applicatif, au lieu d'exécuter une requête INSERT INTO tu appelles (CALL) une procédure.

                      Cette procédure prendra les valeurs à insérer en paramètres, fera l'INSERT, puis fera l'UPDATE ... et surtout pas de TRIGGER ...

                      • Partager sur Facebook
                      • Partager sur Twitter
                      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                        8 novembre 2017 à 11:22:39

                        Ok je comprends..Le soucis c'est que je comptai passer par un trigger justement pour ne pas intervenir au niveau du code applicatif..

                        Si je te suis bien, le problème c'est donc que j'essaye de modifier un autre enregistrement que celui qui est en train d'être inséré, alors est ce qu'on pourrait pas imaginer une solution alternative je m'explique. 

                        Au niveau applicatif, je rentre n'importe quelle valeur dans le champs qui a l'attribute_id 169, à l'insertion en base le trigger va vérifier si le champs GTIN (attribute_id 154) n'est pas NULL, si c'est le cas alors je modifie la value_string qui à l'attribute_id 169 avec le GTIN.

                        En pseudo code ca donnerai un truc de ce genre

                        IF NEW.value_string IS NOT NULL AND NEW.attribute_id=169 // N'importe quelle valeur est saisie dans ce champs 
                        
                            
                        
                            THEN
                        
                                VERIFIER que la dernière valeur en base avec la value_string WHERE attribute_id=154 IS NOT NULL
                                SET NEW.value_string= SELECT la dernière valeur avec value_string WHERE attribute_id=154 
                           
                        
                           END IF;



                        -
                        Edité par JbLau 8 novembre 2017 à 11:26:49

                        • Partager sur Facebook
                        • Partager sur Twitter
                          8 novembre 2017 à 12:25:03

                          Tu peux en effet changer la value_string de l'élément que tu es en train d'insérer en fonction d'une valeur déjà existante en base, sans modifier un enregistrement déjà existant.

                          Je ne comprends toujours pas la logique avec tes id 169 et 154, comment tu fais la correspondance, et je pense que tu devrais clarifier ce point car à mon avis tu dois pouvoir simplifier ta logique ...

                          Mais en tout cas l'idée est là ...

                          On peut imaginer ceci :

                          IF NEW.value_string IS NOT NULL AND NEW.attribute_id=169
                          	SELECT value_string INTO @valeur
                          	FROM pim_catalog_product_value
                          	WHERE attribute_id = 154;
                          	
                          	IF @valeur IS NOT NULL THEN
                          		SET NEW.value_string = @valeur;
                          	END IF;
                          END IF;

                          Attention, il faut que la requête SELECT ne retourne qu'une seule ligne, i.e une seule ligne pour attribute_id = 154. Si il peut y en avoir plusieurs, alors il faut se poser la question de comment la choisi-t-on ? Selon l'id le plus grand ?

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                            8 novembre 2017 à 14:15:37

                            Je crois qu'on approche du but..

                            A propos de la logique avec les attribute_id 169 et 154 c'est lié à l'architecture de la base en EAV.

                            Au lieu d'avoir une colonne en base pour chaque attribut (1 colonne SKU, 1 colonne GTIN etc), l'identification des champs se fait à l'aide de cet attribute_id.

                            Donc j'ai testé ca rapidement et ca fonctionne:

                                    
                            IF NEW.value_string IS NOT NULL AND NEW.attribute_id=169 
                               THEN
                               
                               SET NEW.value_string =(SELECT value_string from pim_catalog_product_value WHERE attribute_id=154 ORDER BY id DESC LIMIT 1);
                               
                               END IF;


                            Il peut bien sûr y avoir plusieurs attribute_id=154 (un pour chaque produit), je dois donc le récupérer avec un ORDER descendant pour prendre le dernier.

                            Il me reste donc à implémenter la condition pour vérifier que cet attribute_id=154 (GTIN) n'est pas nul car s'il est nul je dois aller vérifier que le cip13 (attribute_id=157) n'est pas nul et sinon je vais prendre le cip7(attribute_id=158).

                            Je vais tester ta requête mais ca ressemble fortement à ce que je veux faire.

                            • Partager sur Facebook
                            • Partager sur Twitter
                              8 novembre 2017 à 15:58:52

                              JbLau a écrit:

                              Il peut bien sûr y avoir plusieurs attribute_id=154 (un pour chaque produit), je dois donc le récupérer avec un ORDER descendant pour prendre le dernier

                              Un ORDER sur quel colonne ? id ?

                              JbLau a écrit:

                              Il me reste donc à implémenter la condition pour vérifier que cet attribute_id=154 (GTIN) n'est pas nul

                              Ce que je fais dans mon code ;)
                              • Partager sur Facebook
                              • Partager sur Twitter
                              Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                                9 novembre 2017 à 10:57:26

                                Ok ca fonctionne parfaitement !

                                Oui je fais un order sur la colonne id mais avant je fais une verif sur l'entity_id pour bien récupérer l'attribute_id de l'objet courant.

                                IF NEW.value_string IS NOT NULL AND NEW.attribute_id=169
                                THEN
                                    SELECT v.value_string INTO @valeur
                                    FROM pim_catalog_product_value v
                                    WHERE v.attribute_id = 154
                                    AND NEW.entity_id=v.entity_id
                                    ORDER BY v.id DESC LIMIT 1;
                                     
                                    IF @valeur IS NOT NULL THEN
                                        SET NEW.value_string = @valeur;
                                    END IF;
                                END IF;


                                Un grand merci à toi Benzouye !

                                • Partager sur Facebook
                                • Partager sur Twitter

                                Problème de Trigger

                                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                • Editeur
                                • Markdown