Question

Est-il possible de désactiver un déclencheur momentanément mais pour une seule table.

Par exemple, j'ai table, avec un TableA sur insert, update et déclencheur de suppression. J'ai aussi une table B avec les mêmes déclencheurs, mais ils ne concernent que certaines colonnes dans le tableau A.

J'ai maintenant une requête de mise à jour qui utilise les deux tables. Je sais que les mises à jour dans le tableau A besoin de tirer les déclencheurs mais les mises à jour dans le tableau B ne certainement pas besoin de tirer les déclencheurs. Je voudrais donc désactiver les déclencheurs jusqu'à ce que les mises à jour sont effectuées.

Est-ce possible? J'utilise MySQL 5.1

[ADDENDA]

Voici un tableau de déclenchement A essentiellement

BEGIN
    IF (OLD.status != 1 AND NEW.status = 2) THEN
        IF (OLD.geo_lat IS NOT NULL AND OLD.geo_long IS NOT NULL) THEN
            DELETE FROM geo WHERE datatype IN (3,4) AND foreignid = NEW.id;
        END IF;
    ELSEIF (OLD.Status = 1 AND NEW.Status != 2) THEN
        IF (NEW.geo_lat IS NOT NULL AND NEW.geo_long IS NOT NULL) THEN
            INSERT INTO geo (datatype, foreignid, long, lat, hostid, morton, status) VALUES  (IF(NEW.groupType=1,3,4), NEW.id, NEW.geo_long, NEW.geo_lat, NEW.hostid, 0, NEW.Status);
        END IF;
    ELSEIF (NEW.status != 3) THEN  
        IF (OLD.geo_lat IS NOT NULL AND OLD.geo_long IS NOT NULL AND (NEW.geo_lat IS NULL OR NEW.geo_long IS NULL)) THEN
            DELETE FROM geo WHERE datatype IN (3,4) AND foreignid = NEW.id;
        ElSEIF ((OLD.geo_lat IS NULL OR OLD.geo_long IS NULL) AND NEW.geo_lat IS NOT NULL AND NEW.geo_long IS NOT NULL) THEN
            INSERT INTO geo (datatype, foreignid, longitude, latitude, hostid, morton, status) VALUES  (IF(NEW.groupType=1,3,4), NEW.id, NEW.geo_long, NEW.geo_lat, NEW.hostid, 0, NEW.Status);
        ELSEIF (OLD.geo_lat!=NEW.geo_lat OR OLD.geo_long != NEW.geo_long OR OLD.status != NEW.status) THEN
            UPDATE geo SET lat = NEW.geo_lat, long = NEW.geo_long, status = NEW.status WHERE datatype IN (3,4) AND foreignid = NEW.id;
        END IF;
    END IF;
END

Voici les déclencheurs sur la table B essentiellement

CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`
    FOR EACH ROW
    BEGIN
       CALL sp-set-comment_count(NEW.`gid`);
    END;

Voici la procédure stockée qui est tiré de la table B

DELIMITER $$

CREATE PROCEDURE `sp_set-comment_count` (IN _id INT)
BEGIN
   -- AC   - All Count
   -- OLDAC- Old All Count
   DECLARE AC, OLDAC INT DEFAULT 0;

   SELECT COUNT(*) AS ac
     INTO AC
     FROM usergroups AS ug
LEFT JOIN usergroup_comments AS ugm ON ugm.`gid` = ug.`id`
LEFT JOIN mediagallery AS dm ON ugm.mid = dm.`id`
    WHERE dm.`status` NOT IN (200, 201, 202, 203, 204, 205)
      AND ug.`id` = _id;

   SELECT allCount
     INTO OLDAC
     FROM usergroups
    WHERE ug.`id` = _id;

IF (OLDAC <> AC) THEN 

   UPDATE usergroups
      SET allCount = AC,
    WHERE usergroups.`id` = _id;

END IF;

END $$
Était-ce utile?

La solution

En fait, si vous placez un si puis dans chaque bloc déclencheur, vous pourriez arrêt efficacement tous les déclencheurs. Voici un bloc de code

IF @TRIGGER_DISABLED = 0 THEN
    ...trigger body
END IF;

Dans l'environnement MySQL, vous pourriez

  • run SET @TRIGGER_DISABLED = 1;
  • en assurer la maintenance de données
  • run SET @TRIGGER_DISABLED = 0;

Ainsi, votre déclencheur pour la table A devrait ressembler à ceci:

BEGIN 
    IF @TRIGGER_DISABLED = 0 THEN
    IF (OLD.status != 1 AND NEW.status = 2) THEN 
        IF (OLD.geo_lat IS NOT NULL AND OLD.geo_long IS NOT NULL) THEN 
            DELETE FROM geo WHERE datatype IN (3,4) AND foreignid = NEW.id; 
        END IF; 
    ELSEIF (OLD.Status = 1 AND NEW.Status != 2) THEN 
        IF (NEW.geo_lat IS NOT NULL AND NEW.geo_long IS NOT NULL) THEN 
            INSERT INTO geo (datatype, foreignid, long, lat, hostid, morton, status) VALUES  (IF(NEW.groupType=1,3,4), NEW.id, NEW.geo_long, NEW.geo_lat, NEW.hostid, 0, NEW.Status); 
        END IF; 
    ELSEIF (NEW.status != 3) THEN   
        IF (OLD.geo_lat IS NOT NULL AND OLD.geo_long IS NOT NULL AND (NEW.geo_lat IS NULL OR NEW.geo_long IS NULL)) THEN 
            DELETE FROM geo WHERE datatype IN (3,4) AND foreignid = NEW.id; 
        ElSEIF ((OLD.geo_lat IS NULL OR OLD.geo_long IS NULL) AND NEW.geo_lat IS NOT NULL AND NEW.geo_long IS NOT NULL) THEN 
            INSERT INTO geo (datatype, foreignid, longitude, latitude, hostid, morton, status) VALUES  (IF(NEW.groupType=1,3,4), NEW.id, NEW.geo_long, NEW.geo_lat, NEW.hostid, 0, NEW.Status); 
        ELSEIF (OLD.geo_lat!=NEW.geo_lat OR OLD.geo_long != NEW.geo_long OR OLD.status != NEW.status) THEN 
            UPDATE geo SET lat = NEW.geo_lat, long = NEW.geo_long, status = NEW.status WHERE datatype IN (3,4) AND foreignid = NEW.id; 
        END IF; 
    END IF; 
    END IF; 
END 

Ainsi, votre déclencheur pour la table B devrait ressembler à ceci:

CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`     
    FOR EACH ROW     
    BEGIN     
        IF @TRIGGER_DISABLED = 0 THEN
            CALL sp-set-comment_count(NEW.`gid`);     
        END IF;
    END;     

Si vous voulez que les éléments déclencheurs de la table A à lancer, mais pas au tableau B, puis ajoutez le bloc de code uniquement au déclenchement de la table B.

Autres conseils

Vous pouvez simplifier cette approche.

  1. Ajoutez simplement une étiquette au premier bloc "BEGIN".
  2. test, si la variable de contrôle est NOT NULL.
  3. Si oui, laissez le déclencheur.

Ainsi, vous pouvez éviter d'envelopper le déclencheur code d'origine dans un « IF » -Statment. Seul le déclenchement-tête doit être modifiée d'une manière bien définie -. Ce qui est plus simple et beaucoup plus fiable

Exemple:

CREATE TRIGGER [YOUR_TRIGGER_SPEC]
Trigger: BEGIN

      IF @TRIGGER_DISABLED NOT NULL THEN
         LEAVE Trigger;
      END IF;

      [YOUR CODE]
END;

Amusez-vous: -)

Modifier par RolandoMySQLDBA 2012-05-01 18:38 EDT

J'ai essayé il y a que les mois et il est instable. Voici comment:

Tableau Echantillon

mysql> show create table mytext\G
*************************** 1. row ***************************
       Table: mytext
Create Table: CREATE TABLE `mytext` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `txt` text NOT NULL,
  `txtmd5` char(32) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `txtmd5` (`txtmd5`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> select * from mytext;
+----+------------------------+----------------------------------+
| id | txt                    | txtmd5                           |
+----+------------------------+----------------------------------+
|  1 | Rolando Edwards        | ab14209a029a8f6d42d7c5a5d7a77623 |
|  2 | Pamela Edwards         | 5dcbd06ea48c690032b1b29a514eb0e2 |
|  3 | Dominique Edwards      | 7487431d74ac2d17a9d63123672a4bdf |
|  4 | Diamond Edwards        | bc8d80541a000ed506048134058e2878 |
|  5 | The Quick Brown Fox    | be94284cfa534c1837e744c061f71e17 |
| 11 | Quick Brown Fox Jumped | 495a52136057b242a80e514d7cbe77c7 |
+----+------------------------+----------------------------------+
6 rows in set (0.00 sec)

mysql>

Voici le déclencheur:

DROP TRIGGER IF EXISTS mytext_bi;
DELIMITER $$
CREATE TRIGGER mytext_bi BEFORE INSERT ON mytext FOR EACH ROW
TheTrigger:BEGIN
    DECLARE found_count INT;
    SELECT COUNT(1) INTO found_count
    FROM mytext WHERE txtmd5 = MD5(LEFT(new.txt,10));
    IF found_count = 1 THEN
        LEAVE TheTrigger;
    END IF;
    SET new.txtmd5 = MD5(LEFT(new.txt,10));
END $$
DELIMITER ;

Regardez ce qui se passe lorsque je tente d'insérer 'Dominique Edwards'

mysql> insert into mytext (txt) values ('Dominique Edwards');
Query OK, 1 row affected (0.06 sec)

mysql> select * from mytext;
+----+------------------------+----------------------------------+
| id | txt                    | txtmd5                           |
+----+------------------------+----------------------------------+
|  1 | Rolando Edwards        | ab14209a029a8f6d42d7c5a5d7a77623 |
|  2 | Pamela Edwards         | 5dcbd06ea48c690032b1b29a514eb0e2 |
|  3 | Dominique Edwards      | 7487431d74ac2d17a9d63123672a4bdf |
|  4 | Diamond Edwards        | bc8d80541a000ed506048134058e2878 |
|  5 | The Quick Brown Fox    | be94284cfa534c1837e744c061f71e17 |
| 11 | Quick Brown Fox Jumped | 495a52136057b242a80e514d7cbe77c7 |
| 14 | Dominique Edwards      |                                  |
+----+------------------------+----------------------------------+
7 rows in set (0.00 sec)

mysql>

Ahhh, IT glissai !!! FAÇON

Je vais encore 1 votre réponse non seulement à cause de vos efforts, mais aussi parce que j'ai essayé exactement la même chose (mettre une étiquette près BEGIN) et il n'a pas fonctionné pour moi alors. Quelle façon d'apprendre.

Personne ne devrait mettre la foi complète dans la procédure stockée MySQL Langue (traitement du signal est pas correctement mis en œuvre) et vous a souligné que lorsque vous avez dit « Have Fun ». Parfois, avec des moyens amusants essayer et voir !!! . C'est le véritable esprit de l'apprentissage.

J'ai travaillé autour d'elle comme ceci:

DROP TRIGGER IF EXISTS mytext_bi;
DELIMITER $$
CREATE TRIGGER mytext_bi BEFORE INSERT ON mytext FOR EACH ROW
BEGIN
    DECLARE found_count INT;
    SELECT COUNT(1) INTO found_count
    FROM mytext WHERE txtmd5 = MD5(LEFT(new.txt,10));
    IF found_count = 0 THEN
        SELECT COUNT(1) INTO found_count FROM table_that_does_not_exist;
    END IF;
    SET new.txtmd5 = MD5(LEFT(new.txt,10));
END $$
DELIMITER ;

La nature des procédures stockées est d'aller soit à travers le code complet de naviguer à travers des blocs IF-THEN comme je l'ai fait dans ma réponse ou de l'utilisation de traitement du signal (encore une fois, il est pleinement opérationnel)

Bienvenue sur le DBA !!! StackExchange Encore une fois, +1 comme promis.

Désolé pour la longue modifier, mais je ne pouvais pas mettre mon code exemple dans un commentaire.

d'abord: merci pour le '+1': -)

Et - vous avez raison: la désactivation d'un déclencheur Does'nt L'ACTION PRÉVENIR LUI-MÊME. Il n'y a pas de « bonne » façon de faire ce genre de « abort » -Signal mis en œuvre par MySQL pour le moment.

La commune « contournement » est - comme vous l'avez dans votre réponse - pour élever un SQL Exception. Ainsi, toute l'action sera empêchée par un effet secondaire (l'exception).

: Attention. Cette « solution » crée des problèmes parfois plus - penser à déclencher des transactions et reqired - et, espérons-contrôle - rollbacks. Uuuups! (Qu'est à dire, pourquoi je l'ai utilisé les marques de quotaion pour cette approche).

En outre, il est un truc vraiment difficile de déboguer ces types de mises en œuvre. Avec ce comportement, le développeur, administrateur ou mainteneur doit pouvoir distinct entre les « bonnes » SQL-exceptions et des problèmes vraiment eu lieu. Horrible.

Et enfin et surtout: ce genre de visites par limitiation routines stockées dans MySQL (procédures, fonctions et déclenchement)

En fait: ce manque de contrôle est un blâme pour chaque fournisseur d'un SGBDR. Et Yepp - c'est ce que je veux dire avec « amusement »: -)

Droit, retour aux racines - la question était: « DISABLE un déclencheur » (pas obstacle à l'action). En particulier pour cette exigence particulière de l'approche est sûre et fiable.

Une plus d'informations "derrière le szene": L'approche fourni fonctionne en toute sécurité, car MySQL initialiser les variables sessionbased comme « @TRIGGER_DISABLED » avec NULL -. C'est aussi un sideeffect

Et cramponnez-vous s'il vous plaît à l'esprit: ce genre de variables ne sont visibles à la présente session! Ainsi, vous pouvez désactiver le déclencheur pour la session en cours. Ce type de mise en oeuvre n'a pas d'effets « de serverwide »!

Si vous avez besoin de ce genre de choses (déclencheur bloquantes pour l'ensemble du serveur), vous devez utiliser des objets serverwide visibles et acccessable, comme les variables du serveur (uuups - une autre sorte de « solution » avec des effets secondaires imprédictible) ou - la façon plus propre -. tables

Alors, aussi "désolé" pour ma réponse longue et encore: vous amuser: -)

Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top