4

私のデータベースにはテーブルがあります。Employee再帰的な関連付けにより、従業員は他の従業員の上司になることができます。

テーブルの説明:

mysql> DESC Employee;
+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| SSN         | varchar(64)  | NO   | PRI | NULL    |       |
| name        | varchar(64)  | YES  |     | NULL    |       |
| designation | varchar(128) | NO   |     | NULL    |       |
| MSSN        | varchar(64)  | NO   | MUL | NULL    |       |
+-------------+--------------+------+-----+---------+-------+

従業員テーブルの現在の状態は次のとおりです。

mysql> SELECT * FROM Employee;
    +-----+------+-------------+------+
    | SSN | name | designation | MSSN |
    +-----+------+-------------+------+
    | 1   | A    | OWNER       | 1    |
    | 2   | B    | BOSS        | 1    |  
    | 3   | C    | WORKER      | 2    |  
    | 4   | D    | BOSS        | 2    |  
    | 5   | E    | WORKER      | 4    |   
    | 6   | F    | WORKER      | 1    |  
    | 7   | G    | WORKER      | 4    |  
    +-----+------+-------------+------+
    7 rows in set (0.00 sec)

以下は、テーブル内の行間の階層関係です。

     A
    / \
   B   F
  / \
 c   D
    / \
   G   E

INSERT に次の制約を課したかったのです

  • 従業員は自分自身を BOSS することはできません。これは OWNER のみに許可されます。したがって、クエリのように。
    INSERT INTO Employee VALUES ("8", "H", "BOSS", "8"); 断るべきです。
  • 新しいOWNERものを挿入できます。

私は 5.5 より前の MYSQL バージョンを使用しているため (シグナルをサポートしていません)。そのため、ストアド プロシージャで あるmy_singal()
を使用しています。

このように書かれています:

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// 

そして、制約を適用するwritten a Triggerには、私はそれを知るようになりましたcheck constraints are not yet implemented in MySQL!

DELIMITER $$
CREATE
  TRIGGER `employee_before_insert` BEFORE INSERT
    ON `Employee`
    FOR EACH ROW BEGIN
      CASE
       WHEN NEW.designation = 'OWNER'  THEN
          CALL my_signal('Error: can not insert new OWNER !');

       WHEN NEW.SSN = NEW.MSSN THEN
          CALL my_signal('Error: Row can not reference itself!');
      END CASE; 
  END$$   
DELIMITER ;  

正常にコンパイルされ、データベースにロードされました。しかし、挿入しようとしたとき:

mysql> INSERT INTO Employee VALUES ("12", "K", "BOSS",   "12");
ERROR 1336 (0A000): Dynamic SQL is not allowed in stored function or trigger

私はここここでそれ を学びます

  • SQL プリペアド ステートメント (PREPARE、EXECUTE、DEALLOCATE PREPARE) はストアド プロシージャで使用できますが、ストアド ファンクションまたはトリガーでは使用できません。したがって、ストアド関数とトリガーは動的 SQLを使用できません(ステートメントを文字列として構築してから実行する場合)。

少し努力した後、以下のように別のトリガーを書くことができました。私の要件に従って正常に動作しています

mysql> CREATE
    -> TRIGGER `employee_before_insert` BEFORE INSERT
    ->     ON `Employee`
    ->     FOR EACH ROW BEGIN
    ->      IF UCASE(NEW.designation) = 'OWNER'  THEN  /*UCASE*/
    ->        UPDATE `Error: can not insert new OWNER !` set x=1; 
    ->      END IF;
    ->      IF (NEW.SSN = NEW.MSSN) THEN
    ->        UPDATE `Error: Row can not reference itself!` set x=1;
    ->      END IF;
    -> END$$
Query OK, 0 rows affected (0.08 sec)

mysql> DELIMITER ;
mysql> INSERT INTO Employee VALUES ("12", "K", 'owner',   "11");
ERROR 1146 (42S02): Table 'dumy.Error: can not insert new OWNER !'
  doesn't exist
mysql> INSERT INTO Employee VALUES ("12", "K", 'Ajay',   "12");
ERROR 1146 (42S02): Table 'dumy.Error: Row can not reference itself!' 
  doesn't exist

私はすでに多くの手順で使用しており、関数が再びmy_signal() 必要になる多くの新しいストアド関数とトリガーを作成する必要があるためです。my_signal()

It would also good for easy manipulation if sometime MYSQL version upgraded to 5.5(+).

カスタマイズされたエラーメッセージを出力できる my_signal() を書く他の方法を誰かが提案できますか?

私は次のように試しました:

区切り記号 $$
CREATE PROCEDURE my_signal(in_errortext VARCHAR(255))
DECLARE sql varchar(512);
始める
SET sql=CONCAT('UPDATE ', in_errortext, 'SET x=1');
UPDATE sql SET x =1;
END$$

しかし、役に立たない:(。

これについて私を助けてください.私は非常に感謝します!

私は MYSQL 特に @ ストアド プロシージャが苦手です。

ここでシステムを試してみたい場合は、このデータベースを構築する ためのコマンドをすぐに見つけることができます。

編集 ~コンパイラとして動作する MySQL インタープリター!

トリガーとストアド関数から 動的 SQLステートメントを呼び出すことはできません。

すべての格納されたルーチンで同じインターフェイス my_signal() を維持するために、my_signal(); を変更しました。Static SQLステートメントを追加しDynamic SQL、トリガーから実行されないことを確認しました。許されるべきだと思いましたbecause MySQL is an interpreter not a compiler

新しい my_signal()

DELIMITER $$
CREATE PROCEDURE `my_signal`(in_errortext VARCHAR(255))
BEGIN

    IF in_errortext = 'ERROR_INSERT_OWNER' THEN  /* Static SQL*/
        UPDATE `Error: can not insert new OWNER !` set x=1; 
    END IF;

    IF in_errortext = 'ERROR_INSERT_SELF_REFERENCE' THEN /* Static SQL*/
        UPDATE `Error: Row can not reference itself!` set x=1;

    ELSE /* Dynamic SQL*/    
        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 IF;
END$$  

新しいトリガー

DELIMITER $$
CREATE
    TRIGGER `employee_before_insert` BEFORE INSERT
    ON `Employee`
    FOR EACH ROW BEGIN
        CASE
         WHEN UPPER(NEW.name) = 'OWNER'  THEN
            CALL my_signal('ERROR_INSERT_OWNER');

         WHEN NEW.SSN = NEW.MSSN THEN
            CALL my_signal('ERROR_INSERT_SELF_REFERENCE');
        END CASE; 
    END$$   
DELIMITER ;

うまくいけば、私は挿入しようとしました:

mysql> INSERT INTO Employee VALUES ("9", "X", "WOKER", "9" );
ERROR 1336 (0A000): Dynamic SQL is not allowed in stored function or trigger
mysql> INSERT INTO Employee VALUES ("9", "X", "OWNER", "9" );
ERROR 1336 (0A000): Dynamic SQL is not allowed in stored function or trigger  

おっとっと!コンパイラのように動作しますが、インタプリタではありません。そうじゃない?

編集:答え

幸運にも質問を編集しているときに、RolandoMySQLDBAから回答を得ました。
回答はこちら
最後に:トリガーで動的 SQL を実行できないことは理解できました。my_signal() のコーディングに頼る必要があるかもしれません。MySQL にはまだ他のオプションはありません。

4

1 に答える 1

1

残念ながら、MySQL 5.5 より前では、トリガー内で from を強制する唯一の方法ROLLBACKは、意図的に行ったようにエラーを生成することです。

これにより、2 つの問題が発生します。

  1. カスタムエラーメッセージを返すことができないため、エラーメッセージは開発者にとって非常に混乱しています
  2. ステートメントの操作によって「実際の」エラーが発生する場合、状況によっては、これを上書きしてデバッグをさらに難しくすることさえあります。

これは開発者の視点からのものです - 私はこれに関して DBA と多くの議論をしました。:)

于 2012-11-26T17:14:46.667 に答える