Désactiver déclencheur pour une seule table
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 $$
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.
- Ajoutez simplement une étiquette au premier bloc "BEGIN".
- test, si la variable de contrôle est NOT NULL.
- 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: -)