Frage

Ist es möglich, einen Auslöser momentan zu deaktivieren, aber nur für einen Tisch?

Zum Beispiel habe ich Tabelle, Tablea mit einem Einfügen, Aktualisieren und Löschen von Trigger. Ich habe auch eine Tabelle B mit den gleichen Auslösern, aber sie beeinflussen nur bestimmte Spalten in Tabelle A.

Ich habe jetzt eine Update -Abfrage, die beide Tabellen verwendet. Ich kenne die Updates in Tabelle, um die Auslöser abzufeuern, aber die Updates in Tabelle B müssen die Trigger definitiv nicht abfeuern. Deshalb möchte ich diese Auslöser deaktivieren, bis die Updates abgeschlossen sind.

Ist das möglich? Ich benutze MySQL 5.1

NACHTRAG

Hier ist eine Triggertabelle a im Wesentlichen

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

Hier sind die Trigger in Tabelle B im Wesentlichen

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

Hier ist das gespeicherte Verfahren, das aus Tabelle B abgefeuert wird

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 $$
War es hilfreich?

Lösung

Wenn Sie dann einen IF -Blockieren in jedem Auslöser einfügen, können Sie alle Auslöser effektiv herunterfahren. Hier ist ein solcher Codeblock

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

In der MySQL -Umgebung könnten Sie

  • Lauf SET @TRIGGER_DISABLED = 1;
  • Machen Sie Ihre Datenwartung
  • Lauf SET @TRIGGER_DISABLED = 0;

Ihr Auslöser für Table A sollte also folgendermaßen aussehen:

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 

Ihr Auslöser für Tabelle B sollte also folgendermaßen aussehen:

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;     

Wenn Sie möchten, dass die Auslöser für Tabelle A, jedoch nicht in Tabelle B gestartet werden, fügen Sie den Codeblock nur dem Trigger von Tabelle B hinzu.

Andere Tipps

Sie können diesen Ansatz vereinfachen.

  1. Fügen Sie einfach ein Etikett zum ersten "Beginn" -Block hinzu.
  2. Test, wenn die Steuervariable nicht null ist.
  3. Wenn ja, hinterlassen Sie den Abzug.

Sie können es also vermeiden, den ursprünglichen Triggercode in eine "if" -Antatment zu wickeln. Nur der Triggerkopf muss genau definiert werden - was einfacher und viel zuverlässiger ist.

Beispiel:

CREATE TRIGGER [YOUR_TRIGGER_SPEC]
Trigger: BEGIN

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

      [YOUR CODE]
END;

Habe Spaß :-)

Bearbeiten von Rolandomysqldba 2012-05-01 18:38 EDT

Ich habe das vor Monaten versucht und es ist instabil. Hier ist, wie:

Beispieltabelle

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>

Hier ist der Auslöser:

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 ;

Schauen Sie, was passiert, wo ich versuche, "Dominique Edwards" einzufügen

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, es rutschte sowieso rein !!!

Ich werde Ihre Antwort noch nicht nur wegen Ihrer Anstrengungen, sondern auch, weil ich genau das Gleiche ausprobiert habe (ein Etikett in der Nähe zu setzen BEGIN) Und es hat damals bei mir nicht funktioniert. Was für ein Weg zu lernen.

Niemand sollte den mySQL gespeicherten Verfahrenssprache voll und ganz vertrauen (die Signalverarbeitung wird nicht ordnungsgemäß implementiert), und Sie betonten, als Sie "Spaß haben" sagten, wenn Sie "Spaß haben". Manchmal bedeutet es, Spaß zu haben, probieren Sie es aus und sehen Sie !!!. Das ist der wahre Geist des Lernens.

Ich habe es so gearbeitet:

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 ;

Die Art der gespeicherten Verfahren besteht darin, entweder den vollständigen Code zu durchlaufen, der durch IF-Then-Blöcke wie in meiner Antwort oder in meiner Antwort verwendet wird oder die Signalverarbeitung verwendet wird (es ist wiederum nicht vollständig operativ).

Willkommen im DBA Stackexchange !!! Wieder +1 wie versprochen.

Entschuldigung für die lange Bearbeitung, aber ich konnte meinen Beispielcode nicht in einen Kommentar legen.

Zunächst einmal: Danke für '+1' :-)

Und - Sie haben Recht: Die Deaktivierung eines Auslösers verhindert die Handlung selbst nicht. Es gibt keine "korrekte" Möglichkeit, diese Art von "abortieren" -Signal zu tun, die momentan von MySQL implementiert wird.

Die gemeinsame "Problemumgehung" ist - wie Sie in Ihrer Antwort beschrieben haben, um eine SQL -Ausnahme zu erhöhen. Die gesamte Aktion wird also durch einen Nebeneffekt (die Ausnahme) verhindert.

Aber: Sei vorsichtig. Diese "Lösung" erzeugt manchmal mehr Probleme - denken Sie über transaktionsübergreifende Trigger und hoffentlich kontrolliert - Rollbacks. UUUUPS! (Das ist, warum ich die Kontingennzeichen für diesen Ansatz verwendet habe).

Darüber hinaus ist es ein wirklich schweres Zeug, solche Implementierungen zu debuggen. Mit diesem Verhalten muss der Entwickler, der Administrator oder den Betreuer in der Lage sein, zwischen "guten" SQL-Ausnahmen zu unterscheiden und wirklich Probleme aufgetreten zu sein. Entsetzlich.

Und zuletzt nicht zuletzt: Diese Art von Einschränkung trifft jede gespeicherte Routinen in MySQL (Verfahren, Funktionen und Auslöser)!

Tatsächlich: Dieser Mangel an Kontrolle ist für jeden Anbieter eines RDBMs eine Schuld. Und yepp - das ist was ich mit "haben Spaß haben" :-)

Richtig, zurück zu den Wurzeln - die Frage war: "einen Auslöser deaktivieren" (nicht die Aktion verhindern). Insbesondere für diese besondere Anforderung ist der Ansatz sicher und zuverlässig.

Ein weiterer Informationen "Hinter dem Szene": Der bereitgestellte Ansatz funktioniert sicher, da MySQL mit NULL mit NULL mit "@Triigger_disabled" initialisiert Sitzungsvariablen initialisieren - dies ist auch ein Nebeneffekt.

Und bitte denken Sie daran: Diese Art von Variablen sind nur für die aktuelle Sitzung sichtbar! Sie können also den Auslöser für Ihre aktuelle Sitzung deaktivieren. Diese Art von Implementierungen hat keine "serverweiten" Effekte!

Wenn Sie diese Art von Dingen benötigen (Auslöser für den gesamten Server deaktivieren), müssen Sie serverweite sichtbare und akzessbare Objekte wie Servervariablen (UUUPs - eine andere Art von "Problemumgehung" mit unvorhersehbaren Nebenwirkungen) oder - der saubereren Weg - Tabellen verwenden.

Also, auch "Entschuldigung" für meine lange Antwort und noch einmal: Viel Spaß :-)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit dba.stackexchange
scroll top