GRILLETTI che causano errori INSERT? Possibile?
Domanda
Nel ripulire questa risposta Ho imparato qualcosa su TRIGGER
e sulle procedure memorizzate in MySQL, ma ne sono rimasto sbalordito, mentre PRIMA DI INSERIRE
e PRIMA AGGIORNAMENTO
si innesca potrebbero modificare i dati, apparentemente non potrebbero causare errori di inserimento / aggiornamento (ad es. validazione). In questo caso particolare sono stato in grado di farlo funzionare manipolando i dati in modo tale da causare un duplicato della chiave primaria, che in questo caso particolare aveva senso, ma non ha necessariamente senso in senso generale.
Questo tipo di funzionalità è possibile in MySQL? In qualsiasi altro RDBMS (la mia esperienza è limitata a MySQL purtroppo)? Forse una sintassi di stile THROW EXCEPTION
?
Soluzione
Da questo post di blog
Trigger MySQL: come si interrompe un INSERT, UPDATE o DELETE con a grilletto? Su EfNet & # 8217; s #mysql qualcuno ha chiesto:
Come posso fare in modo che un trigger interrompa l'operazione se la mia regola aziendale fallisce?
In MySQL 5.0 e 5.1 è necessario ricorrere a qualche trucco per fare un grilletto fallito e fornire un significato messaggio di errore. MySQL memorizzato Domande frequenti sulla procedura dice questo sull'errore Manipolazione:
SP 11. Gli SP hanno un & # 8220; rilancio & # 8221; dichiarazione a & # 8220; aumenta errori dell'applicazione & # 8221 ;? Siamo spiacenti, al momento no. Le istruzioni SIGNAL e RESIGNAL standard SQL si trovano su TODO.
Forse MySQL 5.2 includerà SIGNAL dichiarazione che renderà questo hack rubato direttamente da MySQL Stored Procedura Programmazione obsoleta. Che cosa è l'hack? Stai per forzare MySQL per tentare di utilizzare una colonna che non esiste. Brutto? Sì. Lo fa lavoro? Certo.
CREATE TRIGGER mytabletriggerexample BEFORE INSERT FOR EACH ROW BEGIN IF(NEW.important_value) < (fancy * dancy * calculation) THEN DECLARE dummy INT; SELECT Your meaningful error message goes here INTO dummy FROM mytable WHERE mytable.id=new.id END IF; END;
Altri suggerimenti
Ecco come l'ho fatto. Nota SET NEW = 'some error';
. MySQL ti dirà " La variabile "nuovo" non può essere impostata sul valore di "Errore: impossibile eliminare questo elemento. Ci sono record nella tabella di vendita con questo articolo. "& Quot;
Puoi intercettare questo nel tuo codice e quindi mostrare l'errore risultante :)
DELIMITER $
DROP TRIGGER IF EXISTS before_tblinventoryexceptionreasons_delete $
CREATE TRIGGER before_tblinventoryexceptionreasons_delete
BEFORE DELETE ON tblinventoryexceptionreasons
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblinventoryexceptionreasons = old.idtblinventoryexceptionreasons) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory exception reasons table with this item.';
END IF;
END$
DELIMITER ;
DELIMITER $
DROP TRIGGER IF EXISTS before_storesalesconfig_delete $
CREATE TRIGGER before_storesalesconfig_delete
BEFORE DELETE ON tblstoresalesconfig
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM tblstoresales WHERE tblstoresales.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the sales table with this item.';
END IF;
IF (SELECT COUNT(*) FROM tblinventory WHERE tblinventory.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory table with this item.';
END IF;
IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory exceptions table with this item.';
END IF;
IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
END IF;
END$
DELIMITER ;
DELIMITER $
DROP TRIGGER IF EXISTS before_tblinvoice_delete $
CREATE TRIGGER before_tblinvoice_delete
BEFORE DELETE ON tblinvoice
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblinvoice = old.idtblinvoice) > 0
THEN
SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
END IF;
END$
DELIMITER ;
Dato che questo articolo arriva in cima quando cerco la gestione degli errori nei trigger di MySQL, ho pensato di condividere alcune conoscenze.
Se si verifica un errore, è possibile forzare MySQL a utilizzare un SEGNALE , ma se non lo specifichi come classe come SQLEXCEPTION, non accadrà nulla, poiché non tutti gli SQLSTATE sono considerati errati e anche allora dovresti assicurarti di RESIGNAL se hai blocchi BEGIN / END nidificati .
In alternativa, e probabilmente ancora più semplice, all'interno del trigger, dichiarare un gestore di uscita e dimettere l'eccezione.
CREATE TRIGGER `my_table_AINS` AFTER INSERT ON `my_table` FOR EACH ROW
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
RESIGNAL;
DECLARE EXIT HANDLER FOR SQLWARNING
RESIGNAL;
DECLARE EXIT HANDLER FOR NOT FOUND
RESIGNAL;
-- Do the work of the trigger.
END
E se nel tuo corpo si verifica un errore, verrà riportato in alto e uscirà con un errore. Questo può essere utilizzato anche nelle stored procedure e quant'altro.
Funziona con qualsiasi versione 5.5+.
Ciò interromperà il tuo INSERT sollevando un'eccezione (da http: // www.experts-exchange.com/Database/MySQL/Q_23788965.html )
DROP PROCEDURE IF EXISTS `MyRaiseError`$
CREATE PROCEDURE `MyRaiseError`(msg VARCHAR(62))
BEGIN
DECLARE Tmsg VARCHAR(80);
SET Tmsg = msg;
IF (CHAR_LENGTH(TRIM(Tmsg)) = 0 OR Tmsg IS NULL) THEN
SET Tmsg = 'ERROR GENERADO';
END IF;
SET Tmsg = CONCAT('@@MyError', Tmsg, '@@MyError');
SET @MyError = CONCAT('INSERT INTO', Tmsg);
PREPARE stmt FROM @MyError;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$
Utilizzo:
call MyRaiseError('Here error message!');
Non funziona con i trigger (SQL dinamico non consentito nella funzione memorizzata o trigger)
Uso una soluzione molto sporca:
Se NEW.test = 1 allora
CALL TEST_CANNOT_BE_SET_TO_1;
finisci se;
Quando test = 1 Mysql genera la seguente eccezione:
L'amministrazione PROCEDURE.TEST_CANNOT_BE_SET_TO_1 non esiste
Non sofisticato ma veloce e utile.
in MS SQL potresti farlo funzionare usando la sintassi corretta:
IF UPDATE(column_name)
BEGIN
RAISEERROR
ROLLBACK TRAN
RETURN
END