Triggern, die Ursache INSERTs zum Scheitern verurteilt? Möglich?
Frage
diese Antwort habe ich gelernt, ein wenig über TRIGGER
s und gespeicherte Prozeduren in MySQL, aber war fassungslos, dass, während BEFORE INSERT
und BEFORE UPDATE
Trigger Daten ändern, könnten sie scheinbar nicht dazu führen, das Insert / Update fehlschlagen (dh. Validierung). In diesem speziellen Fall war ich in der Lage dies durch Manipulation der Daten in einer solchen Art und Weise zu arbeiten, um zu bekommen als einen Primärschlüssel Duplikat zu verursachen, die in diesem speziellen Fall sinnvoll, aber nicht unbedingt Sinn in einem allgemeinen Sinn machen.
Ist diese Art von Funktionalität möglich in MySQL? In allen anderen RDBMS (meine Erfahrung beschränkt sich auf MySQL leider)? Vielleicht eine THROW EXCEPTION
Stil Syntax?
Lösung
Von diesem Blog-Post
MySQL Trigger: Wie Sie eine INSERT, UPDATE Sie abbrechen oder DELETE mit einem auslösen? Auf EfNet des #mysql jemand fragte:
Wie kann ich einen Trigger mache den Vorgang abzubrechen, wenn meine Geschäftsregel nicht?
In MySQL 5.0 und 5.1 müssen Sie greifen, um einige Tricks ein machen Auslöser fehlschlagen und eine sinnvolle liefern Fehlermeldung. Die MySQL Stored Verfahren FAQ sagt über Fehler Handhabung:
SP 11. Do SPs haben eine „erhöhen“ Anweisung „Anwendungsfehler erhöhen“? Sorry, derzeit nicht. Die SQL-Standard SIGNAL und RESIGNAL Aussagen sind auf der TODO.
Vielleicht MySQL 5.2 wird SIGNAL umfassen Erklärung, die diesen Hack machen gerade aus MySQL gestohlen Stored Verfahren Programmierung überflüssig. Was ist der Hack? Sie gehen zu zwingen MySQL zu versuchen, eine Spalte zu verwenden, die ist nicht vorhanden. Hässlich? Ja. Macht es Arbeit? Sicher.
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;
Andere Tipps
Hier ist die Art, wie ich es tat. Beachten Sie die SET NEW='some error';
. MySQL werden Sie sagen, „Variable‚neue‘können nicht auf den Wert festgelegt werden". Fehler: Kann dieses Element nicht löscht Es gibt Aufzeichnungen in dem Verkaufstisch mit diesem Titel.“
Sie können diese Falle in Ihrem Code und dann zeigt die resultierenden Fehler:)
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 ;
Da dieser Artikel oben nach oben kommt, wenn ich für die Fehlersuche Handhabung in MySQL löst, dachte ich, ich würde etwas Wissen teilen.
Wenn ein Fehler auftritt, können Sie MySQL zwingen, ein SIGNAL , aber wenn Sie es als eine Klasse als SQLEXCEPTION nicht angeben, dann wird nichts passieren, da nicht alle SQLSTATEs schlecht betrachtet werden, und selbst dann würden Sie müssen sicherstellen, dass auf RESIGNAL , wenn Sie verschachtelte BEGIN / END-Blöcke .
Alternativ und einfacher wahrscheinlich immer noch, in Ihrem Trigger, erklären einen Exit-Handler und RESIGNAL die Ausnahme.
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
Und wenn in Ihrem Körper einen Fehler auftritt, wird es wieder mit einem Fehler bis an die Spitze und Ausfahrt geworfen werden. Dies kann auch in Stored Procedures und so weiter verwendet werden.
Das funktioniert mit etwas Version 5.5 +.
Dies wird abbrechen Ihre INSERT durch Auslösen einer Ausnahme (von 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$$
Verbrauch:
call MyRaiseError('Here error message!');
doen 'T Arbeit in Triggern (Dynamic SQL nicht in gespeicherten Funktion oder Trigger erlaubt)
Ich verwende eine sehr schmutzige Lösung:
If NEW.test=1 then
CALL TEST_CANNOT_BE_SET_TO_1;
end if;
Wenn Test = 1 Mysql die folgende Ausnahme ausgelöst:
VERFAHREN administratie.TEST_CANNOT_BE_SET_TO_1 existiert nicht
Nicht anspruchsvoll, aber schnell und sehr nützlich.
in MS SQL man könnte es mit richtigen Syntax funktioniert:
IF UPDATE(column_name)
BEGIN
RAISEERROR
ROLLBACK TRAN
RETURN
END