14

この回答をクリーンアップTRIGGERする際に、MySQL の s とストアド プロシージャについて少し学びましたが、BEFORE INSERTBEFORE UPDATEトリガーはデータを変更できますが、挿入/更新を失敗させることはできないように見えることに驚きました (つまり、検証)。この特定のケースでは、主キーの重複を引き起こすような方法でデータを操作することでこれを機能させることができました。この特定のケースでは意味がありましたが、一般的な意味では必ずしも意味がありません.

この種の機能は MySQL で可能ですか? 他の RDBMS では (残念ながら私の経験は MySQL に限定されています)? おそらくTHROW EXCEPTIONスタイル構文?

4

6 に答える 6

19

このブログ記事から

MySQL トリガー: トリガーを使用して INSERT、UPDATE、または DELETE を中止するにはどうすればよいですか? EfNet の #mysql で、誰かが尋ねました:

ビジネス・ルールが失敗した場合にトリガーが操作を中止するようにするにはどうすればよいですか?

MySQL 5.0 および 5.1 では、トリガーを失敗させて意味のあるエラー メッセージを配信するために、いくつかのトリックに頼る必要があります。MySQL Stored Procedure FAQ には、エラー処理について次のように書かれています。

SP 11. SP には、「アプリケーション エラーを発生させる」ための「発生」ステートメントがありますか? 申し訳ありませんが、現時点ではありません。SQL 標準の SIGNAL および RESIGNAL ステートメントは TODO にあります。

おそらく、MySQL 5.2 には SIGNAL ステートメントが含まれているため、MySQL ストアド プロシージャ プログラミングから直接盗まれたこのハックは廃止されるでしょう。ハックとは何ですか?MySQL に、存在しない列を使用させようとします。醜い?はい。それは機能しますか?もちろん。

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;
于 2008-10-23T13:56:09.007 に答える
8

これが私がやった方法です。に注意してくださいSET NEW='some error';。MySQL は、「変数 'new' は 'Error: Cannot delete this item. There are records in the sales table with this item.'」というメッセージを表示します。

これをコードでトラップして、結果のエラーを表示できます:)

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 ;
于 2010-04-22T20:07:26.583 に答える
1

トリガーでは機能しません (動的 SQL は、ストアド関数またはトリガーでは許可されていません)

私は非常に汚い解決策を使用します:

If NEW.test=1 then CALL TEST_CANNOT_BE_SET_TO_1; end if;

test=1 の場合、Mysql は次の例外をスローします。

PROCEDURE administratie.TEST_CANNOT_BE_SET_TO_1 が存在しません

洗練されていませんが、高速で便利です。

于 2012-07-03T20:25:40.537 に答える
1

これにより、例外が発生してINSERTが中止されます(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$$

使用法:

call MyRaiseError('Here error message!');
于 2008-10-23T13:59:43.680 に答える
-1

MS SQL では、適切な構文を使用して動作させることができます。

IF UPDATE(column_name)
BEGIN
  RAISEERROR
  ROLLBACK TRAN
  RETURN
END

http://msdn.microsoft.com/en-us/magazine/cc164047.aspx

于 2008-10-23T14:01:49.917 に答える