Einen Fehler in einem MySQL-Trigger werfen

  • Wenn ich eine trigger before the update in einer Tabelle habe, wie kann ich dann einen Fehler auslösen, der die Aktualisierung dieser Tabelle verhindert?

    11 March 2016
    sujith karivelilMatt MacLean
6 answers
  • Ab MySQL 5.5 können Sie die SIGNAL Syntax zum Auslösen einer Ausnahme :

     signal sqlstate '45000' set message_text = 'My Error Message';
     

    Der Zustand 45000 ist ein generischer Status, der "nicht behandelten Benutzer" darstellt -definierte Ausnahme ".


    Hier ist ein vollständigeres Beispiel für den Ansatz:

     delimiter //
    use test//
    create table trigger_test
    (
        id int not null
    )//
    drop trigger if exists trg_trigger_test_ins //
    create trigger trg_trigger_test_ins before insert on trigger_test
    for each row
    begin
        declare msg varchar(128);
        if new.id < 0 then
            set msg = concat('MyTriggerError: Trying to insert a negative value in trigger_test: ', cast(new.id as char));
            signal sqlstate '45000' set message_text = msg;
        end if;
    end
    //
    
    delimiter ;
    -- run the following as seperate statements:
    insert into trigger_test values (1), (-1), (2); -- everything fails as one row is bad
    select * from trigger_test;
    insert into trigger_test values (1); -- succeeds as expected
    insert into trigger_test values (-1); -- fails as expected
    select * from trigger_test;
     
    20 November 2016
    DrewRuiDC
  • Hier ist ein Hack , der funktionieren kann. Es ist nicht sauber, aber es sieht so aus, als könnte es funktionieren:

    Im Grunde versuchen Sie einfach, eine Spalte zu aktualisieren, die nicht existiert.

    25 December 2012
    weddingcakesJustin
  • Leider funktioniert die von @RuiDC bereitgestellte Antwort in MySQL-Versionen vor 5.5 nicht, da SIGNAL für gespeicherte Prozeduren nicht implementiert ist.

    Die Lösung habe ich found soll ein Signal simulieren, das einen table_name doesn't exist -Fehler auslöst, wobei eine angepasste Fehlermeldung in das table_name geschrieben wird.

    Der Hack könnte mit implementiert werden Trigger oder mit einer gespeicherten Prozedur. Im Folgenden beschreibe ich beide Optionen anhand des von @RuiDC verwendeten Beispiels.

    Trigger verwenden

     DELIMITER $$
    -- before inserting new id
    DROP TRIGGER IF EXISTS before_insert_id$$
    CREATE TRIGGER before_insert_id
        BEFORE INSERT ON test FOR EACH ROW
        BEGIN
            -- condition to check
            IF NEW.id < 0 THEN
                -- hack to solve absence of SIGNAL/prepared statements in triggers
                UPDATE `Error: invalid_id_test` SET x=1;
            END IF;
        END$$
    
    DELIMITER ;
     

    Verwenden einer gespeicherten Prozedur

    Gespeicherte Prozeduren ermöglichen Ihnen die Verwendung von dynamischem SQL, das die Kapselung der Fehlergenerierungsfunktionalität in ermöglicht ein Verfahren. Der Kontrapunkt ist, dass wir die Einfüge- / Aktualisierungsmethoden für Anwendungen steuern sollten, so dass sie nur unsere gespeicherte Prozedur verwenden (keine direkten Berechtigungen für INSERT / UPDATE vergeben).

     DELIMITER $$
    -- my_signal procedure
    CREATE PROCEDURE `my_signal`(in_errortext VARCHAR(255))
    BEGIN
        SET @sql=CONCAT('UPDATE `', in_errortext, '` SET x=1');
        PREPARE my_signal_stmt FROM @sql;
        EXECUTE my_signal_stmt;
        DEALLOCATE PREPARE my_signal_stmt;
    END$$
    
    CREATE PROCEDURE insert_test(p_id INT)
    BEGIN
        IF NEW.id < 0 THEN
             CALL my_signal('Error: invalid_id_test; Id must be a positive integer');
        ELSE
            INSERT INTO test (id) VALUES (p_id);
        END IF;
    END$$
    DELIMITER ;
     
    28 January 2012
    el.atomo
  • Das folgende Verfahren ist (auf mysql5) eine Möglichkeit, benutzerdefinierte Fehler auszulösen und diese gleichzeitig zu protokollieren:

     create table mysql_error_generator(error_field varchar(64) unique) engine INNODB;
    DELIMITER $$
    CREATE PROCEDURE throwCustomError(IN errorText VARCHAR(44))
    BEGIN
        DECLARE errorWithDate varchar(64);
        select concat("[",DATE_FORMAT(now(),"%Y%m%d %T"),"] ", errorText) into errorWithDate;
        INSERT IGNORE INTO mysql_error_generator(error_field) VALUES (errorWithDate);
        INSERT INTO mysql_error_generator(error_field) VALUES (errorWithDate);
    END;
    $$
    DELIMITER ;
    
    
    call throwCustomError("Custom error message with log support.");
     
    09 November 2012
    Marinos An
  •  CREATE TRIGGER sample_trigger_msg 
        BEFORE INSERT
    FOR EACH ROW
        BEGIN
    IF(NEW.important_value) < (1*2) THEN
        DECLARE dummy INT;
        SELECT 
               Enter your Message Here!!!
     INTO dummy 
            FROM mytable
          WHERE mytable.id=new.id
    END IF;
    END;
     
    12 August 2016
    BHUVANESH MOHANKUMAR
  • Eine andere (Hack) -Methode (falls Sie aus irgendeinem Grund nicht über 5.5 oder älter sind), die Sie verwenden können:

    Wenn Sie ein erforderliches Feld haben, dann innerhalb Ein Trigger setzt das erforderliche Feld auf einen ungültigen Wert wie NULL. Dies funktioniert sowohl für INSERT als auch für UPDATE. Beachten Sie, dass, wenn NULL ein gültiger Wert für das erforderliche Feld ist (aus irgendeinem verrückten Grund), dieser Ansatz nicht funktioniert.

     BEGIN
        -- Force one of the following to be assigned otherwise set required field to null which will throw an error
        IF (NEW.`nullable_field_1` IS NULL AND NEW.`nullable_field_2` IS NULL) THEN
            SET NEW.`required_id_field`=NULL;
        END IF;
    END
     

    Wenn Sie 5.5 oder höher verwenden, können Sie den Signalstatus wie in anderen Antworten beschrieben verwenden:

     BEGIN
        -- Force one of the following to be assigned otherwise use signal sqlstate to throw a unique error
        IF (NEW.`nullable_field_1` IS NULL AND NEW.`nullable_field_2` IS NULL) THEN
            SIGNAL SQLSTATE '45000' set message_text='A unique identifier for nullable_field_1 OR nullable_field_2 is required!';
        END IF;
    END
     
    10 April 2016
    baflink