Vă mulțumim pentru susținere

Aruncați o eroare într-un declanșator MySQL

Dacă am un trigger înainte de actualizarea pe un tabel, cum pot arunca o eroare care împiedică actualizarea din tabelul respectiv?

0
adăugat editat

6 răspunsuri

Următoarea procedură este (pe mysql5) o modalitate de a arunca erori personalizate și le înregistrați în același timp:

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.");
0
adăugat

Here is one hack that may work. It isn't clean, but it looks like it might work:

În esență, încercați doar să actualizați o coloană care nu există.

0
adăugat
Salut puteți face un exemplu practic cu privire la modul de scriere a declanșatorului în link-ul? Am două coloane (idUser și idGuest) care trebuie să se excludă reciproc în comenzile de tabel, dar sunt destul de nou pentru a declanșa și am găsit dificultăți în scris!
adăugat autor Nicola Peluchetti
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;
0
adăugat
Deși acest fragment de cod poate rezolva această întrebare, include o explicație într-adevăr ajută la îmbunătățirea calității din postarea ta. Amintiți-vă că răspundeți la întrebări pentru cititori în viitor și acei oameni ar putea să nu știe motivele pentru sugestia dvs. de cod. De asemenea, încercați să nu vă mulțumiți codul cu comentarii explicative, deoarece acest lucru reduce lizibilitatea atât a codului, cât și a explicațiilor!
adăugat autor FrankerZ

Din păcate, răspunsul oferit de @RuiDC nu funcționează în versiunile MySQL înainte de 5.5 deoarece nu există o implementare a SIGNAL pentru procedurile stocate.

Soluția pe care am găsită este pentru a simula un semnal care aruncă o eroare table_name nu există , împingând un mesaj de eroare personalizat în table_name .

Hack-ul ar putea fi implementat folosind declanșatoare sau utilizând o procedură stocată. Am descrie ambele opțiuni de mai jos, urmând exemplul utilizat de @RuiDC.

Utilizând declanșatoarele

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 ;

Utilizarea unei proceduri stocate

Procedurile stocate vă permit să utilizați sql dinamic, ceea ce face posibilă încapsularea funcției de generare a erorilor într-o singură procedură. Contrapunctul este că trebuie să controlam metodele de inserare / actualizare a aplicațiilor, astfel încât să utilizeze doar procedura noastră stocată (neacordând privilegii directe la INSERT / UPDATE).

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 ;
0
adăugat
În procedura insert_test dacă new.id <0 nu este sintaxă validă dacă ar trebui să fie P_id <0
adăugat autor Tim Child
Prima hack nu funcționează # 1103 - nume de tabel incorect "Eroare: invalid_id_test" .
adăugat autor happy_marmoset
@happy_marmoset, nu este scopul de a ridica o eroare? Prin utilizarea textului de eroare ca nume de tabel, eroarea este declanșată și inserția este împiedicată. Așa cum am înțeles aceasta este o modalitate de a face acest lucru, în cazul în care mysql dvs. <5.5
adăugat autor Jette

Începând cu MySQL 5.5, puteți utiliza SIGNAL sintaxa pentru a arunca o excepție :

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

Statul 45000 este un stat generic care reprezintă "excepție definită de utilizator nefolosită".


Iată un exemplu mai complet al abordării:

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;
0
adăugat

O altă metodă (hack) (dacă nu sunteți pe 5.5+ dintr-un motiv oarecare) pe care o puteți folosi:

Dacă aveți un câmp obligatoriu, atunci într-un trigger setați câmpul necesar la o valoare nevalidă, cum ar fi NULL. Acest lucru va funcționa atât pentru INSERT, cât și pentru UPDATE. Rețineți că dacă NULL este o valoare valabilă pentru câmpul necesar (pentru unele motive nebune) atunci această abordare nu va funcționa.

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

Dacă sunteți la 5.5 + atunci puteți folosi starea semnalului așa cum este descris în alte răspunsuri:

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
0
adăugat