除了使用准备语句在触发与MySQL(Alternative to using Prepared St

2019-07-30 11:12发布

我试图创建一个MySQL插入之前触发下面的代码这将做我想做的事情,如果我能找到一种方法来执行由触发产生的事先准备好的声明。

是从触发器内执行预处理语句任何其他方式? 谢谢

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

UPDATE /澄清 :的数据将被如下存储在表中。

+------------+-----+------+----------------+
| 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)
+------------+-----+------+----------------+

在每次插入命令表将被透水行的哈希值appeding到整个新行的CONCAT()生成该行的哈希值,然后重新散列整个字符串。 这将创建哈希值的运行记录以供审核/应用程序的其它部分使用。

我的约束,这有INSERT之前完成为行不能事后更新。

更新 :我目前使用下面的代码,直到我能找到一种方法,通过列名动态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

Answer 1:

简短的回答是,你不能使用动态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列的索引的,做一个反向扫描操作的方法。 如果不使用索引,我会尝试重写该查询(可能为连接,以获得最佳的性能。

 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语句制备(准备,执行DEALLOCATE PREPARE)可以在存储过程中使用,但没有存储功能或触发器。 因此,存储函数和触发器不能使用动态SQL(在这里您构建语句字符串,然后执行它们)。
</剪断>



文章来源: Alternative to using Prepared Statement in Trigger with MySQL