mysql的预准备语句,在MySQL触发器中使用预准备语句的替代方法

I'm trying to create a MySQL Before Insert trigger with the following code which would do what I want it to do if I could find a way to execute the prepared statement generated by the trigger.

Are the any alternative ways to execute prepared statements from within triggers? Thanks

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 / CLARIFICATION: The data will be stored in a table as below.

+------------+-----+------+----------------+

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

+------------+-----+------+----------------+

On each insert command the table will generate a Hash value for that row by appeding the pervious row's Hash value to a CONCAT() of the entire new row, then re-hashing the entire string. This will create a running record of Hash values for auditing purposes / use in another part of the application.

My constraints are that this has to be done before the INSERT as rows cannot be updated afterwards.

UPDATE: I'm currently using the following code until I can find a way to pass the column names to CONCAT dynamically:

BEGIN

SET @Record = (

SELECT AUTO_INCREMENT FROM information_schema.TABLES

WHERE TABLE_SCHEMA=DATABASE()

AND TABLE_NAME='core_Test' #

);

SET @PrevRecrd = @Record-1;

IF (new.ID IS NULL) THEN

SET new.ID = @Record;

END IF;

SET @PrevHash = (

SELECT Hash FROM core_Test #

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

解决方案

The short answer is that you can't use dynamic SQL in a TRIGGER.

I'm confused by the query of the auto_increment value, and assigning a value to the ID column. I don't understand why you need to set the value of the ID column. Isn't that the column that is defined as the AUTO_INCREMENT? The database will handle the assignment.

It's also not clear that your query is guaranteed to return unique values, especially when concurrent inserts are run. (I've not tested, so it might work.)

But the code is peculiar.

It looks as if what you're trying to accomplish is to get the value of a column from the most recently inserted row. I think there are some restrictions on querying the same table the trigger is defined on. (I know for sure there is in Oracle; MySQL may be more liberal.)

If I needed to do something like that, I would try something like this:

SELECT @prev_hash := t.hash AS prev_hash

FROM core_Test t

ORDER BY t.ID DESC LIMIT 1;

SET NEW.hash = @prev_hash;

But again, I'm not sure this will work (I would need to test). If it works on a simple case, that's not proof that it works all the time, in the case of concurrent inserts, in the case of an extended insert, et al.

I wrote the query the way I did so that it can make use of an index on the ID column, to do a reverse scan operation. If it doesn't use the index, I would try rewriting that query (probably as a JOIN, to get the best possible performance.

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

Excerpt from MySQL 5.1 Reference Manual

E.1 Restrictions on Stored Programs

SQL prepared statements (PREPARE, EXECUTE, DEALLOCATE PREPARE) can be

used in stored procedures, but not stored functions or

triggers. Thus, stored functions and triggers cannot use

dynamic SQL (where you construct statements as strings and then

execute them).

[sic]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值