3

トリガーによって生成された準備済みステートメントを実行する方法を見つけることができれば、次のコードを使用して MySQL Before Insert トリガーを作成しようとしています。

トリガー内から準備済みステートメントを実行する別の方法はありますか? ありがとう

BEGIN
    SET @CrntRcrd = (SELECT AUTO_INCREMENT FROM information_schema.TABLES 
              WHERE TABLE_SCHEMA=DATABASE()
              AND TABLE_NAME='core_Test');

  SET @PrevRcrd = @CrntRcrd-1;

    IF (NEW.ID IS NULL) THEN
        SET NEW.ID = @CrntRcrd;
    END IF;

    SET @PrevHash = (SELECT Hash FROM core_Test WHERE Record=@PrevRcrd);

    SET @ClmNms = (SELECT CONCAT('NEW.',GROUP_CONCAT(column_name 
                  ORDER BY ORDINAL_POSITION SEPARATOR ',NEW.'),'')
                  FROM information_schema.columns 
                  WHERE table_schema = DATABASE() 
                  AND table_name = 'core_Test');

  SET @Query = CONCAT("SET @Query2 = CONCAT_WS(',','",@PrevHash,"','", @CrntRcrd, "',", @ClmNms, ");");

  PREPARE stmt1 FROM @Query;
  EXECUTE stmt1;
  DEALLOCATE PREPARE stmt1; 

  SET NEW.Hash = @Query2;
END

更新/明確化: データは以下のようにテーブルに保存されます。

+------------+-----+------+----------------+
| Record (AI)| ID  | Data | HASH           |
+------------+-----+------+----------------+
| 1          | 1   | ASDF | =DHFBGKJSDFHBG | (Hash Col 1)
| 2          | 2   | NULL | =UEGFRYJKSDFHB | (Hash Col 1 + Col 2)
| 3          | 1   | VBNM | =VKJSZDFVHBFJH | (Hash Col 2 + Col 3)
| 4          | 4   | TYUI | =KDJFGNJBHMNVB | (Hash Col 3 + Col 4)
| 5          | 5   | ZXCV | =SDKVBCVJHBJHB | (Hash Col 4 + Col 5)
+------------+-----+------+----------------+

各挿入コマンドで、テーブルは前の行のハッシュ値を新しい行全体の CONCAT() に追加し、文字列全体を再ハッシュすることによって、その行のハッシュ値を生成します。これにより、監査目的/アプリケーションの別の部分で使用するためのハッシュ値の実行中の記録が作成されます。

私の制約は、行を後で更新できないため、INSERT の前にこれを行う必要があるということです。

UPDATE : 列名を CONCAT に動的に渡す方法が見つかるまで、現在次のコードを使用しています。

BEGIN

  SET @Record = (
    SELECT AUTO_INCREMENT FROM information_schema.TABLES 
    WHERE TABLE_SCHEMA=DATABASE()
    AND TABLE_NAME='core_Test'    #<--- UPDATE TABLE_NAME HERE
  );
  SET @PrevRecrd = @Record-1;

    IF (new.ID IS NULL) THEN
    SET new.ID = @Record;
  END IF;

  SET @PrevHash = (
    SELECT Hash FROM core_Test    #<--- UPDATE TABLE_NAME HERE
    WHERE Record=@PrevRecrd
  );

  SET new.Hash = SHA1(CONCAT_WS(',',@PrevHash, @Record,
    /* --- UPDATE TABLE COLUMN NAMES HERE (EXCLUDE "new.Record" AND "new.Hash") --- */
    new.ID, new.Name, new.Data
  ));

END
4

1 に答える 1

2

簡単に言うと、TRIGGER では動的 SQL を使用できないということです。

auto_increment 値のクエリと ID 列への値の割り当てに混乱しています。ID 列の値を設定する必要がある理由がわかりません。AUTO_INCREMENT として定義されている列ではないでしょうか。データベースが割り当てを処理します。

特に同時挿入が実行される場合、クエリが一意の値を返すことが保証されていることも明らかではありません。(私はテストしていないので、うまくいくかもしれません。)

しかし、コードは独特です。

達成しようとしているのは、最後に挿入された行から列の値を取得することのようです。トリガーが定義されている同じテーブルのクエリにはいくつかの制限があると思います。(確かに Oracle にあることは知っています。MySQL はよりリベラルかもしれません。)

そのようなことをする必要がある場合は、次のようなことを試します。

 SELECT @prev_hash := t.hash AS prev_hash 
   FROM core_Test t
  ORDER BY t.ID DESC LIMIT 1;

 SET NEW.hash = @prev_hash; 

しかし、繰り返しますが、これが機能するかどうかはわかりません (テストする必要があります)。単純なケースで機能する場合、同時挿入の場合、拡張挿入の場合など、常に機能するという証拠にはなりません。

ID 列のインデックスを使用してリバース スキャン操作を実行できるように、私が行った方法でクエリを作成しました。インデックスを使用しない場合は、可能な限り最高のパフォーマンスを得るために、そのクエリを (おそらく JOIN として) 書き直します。

 SELECT @prev_hash := t.hash AS prev_hash
   FROM ( SELECT r.ID FROM core_Test r ORDER BY r.ID DESC LIMIT 1 ) s
   JOIN core_Test t
     ON t.ID = s.ID


MySQL 5.1 リファレンス マニュアルE.1 ストアド プログラムの制限からの抜粋

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

于 2012-07-17T02:58:54.030 に答える