当前位置: 首页 > 面试题库 >

从触发器调用的存储过程中动态语句的解决方法

谈禄
2023-03-14
问题内容

MysqlPREPAREEXECUTE语句不能在触发器调用的存储过程中使用。结果将是Error Code: 1336. Dynamic SQL is not allowed in stored function or trigger

有谁知道解决这个问题的可行方案?


问题答案:

您不能运行PREPARE/EXECUTE从里面TRIGGER,但是你可以从一个EVENT(如果你正在运行MySQL 5.5或更高版本)。

这是从中运行PREPARE/的示例:EXECUTE``EVENT

DROP TABLE IF EXISTS tbl1;
DROP TABLE IF EXISTS tbl2;
DROP TABLE IF EXISTS cmds;
DROP PROCEDURE IF EXISTS proc;
DROP TRIGGER IF EXISTS trig;

CREATE TABLE tbl1 (i INT, v VARCHAR(255));
CREATE TABLE tbl2 (i INT, v VARCHAR(255));

CREATE TABLE cmds (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    done BOOL NOT NULL DEFAULT FALSE,
    cmd TEXT,
    PRIMARY KEY (id),
    INDEX (done, id)
);

DELIMITER //

CREATE PROCEDURE proc()
NOT DETERMINISTIC
MODIFIES SQL DATA
proc: BEGIN
    DECLARE b_not_found     BOOL DEFAULT FALSE;
    DECLARE i_id            INT UNSIGNED;
    DECLARE t_cmd           TEXT;
    DECLARE v_lock_name     VARCHAR(255) DEFAULT 'proc_lock';

    DECLARE cur CURSOR FOR
        SELECT id, cmd FROM cmds WHERE NOT done ORDER BY id;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET b_not_found = TRUE;

    IF (NOT GET_LOCK(v_lock_name, 0)) THEN
        LEAVE proc;
    END IF;

    OPEN cur;

    loop1: LOOP
        FETCH cur INTO i_id, t_cmd;
        IF b_not_found THEN
            LEAVE loop1;
        END IF;

        SET @cmd = t_cmd;

        PREPARE stmt FROM @cmd;
        EXECUTE stmt;
        DROP PREPARE stmt;

        UPDATE cmds SET done = TRUE WHERE id = i_id;
    END LOOP;

    CLOSE cur;

    DO RELEASE_LOCK(v_lock_name);
END;
//

CREATE TRIGGER trig
    BEFORE INSERT ON tbl1
    FOR EACH ROW
BEGIN
    INSERT INTO cmds SET cmd = 
        CONCAT("INSERT INTO tbl2 SET i = ", -NEW.i, ", v = ", QUOTE(NEW.v));
END;
//

DROP EVENT IF EXISTS evnt //

CREATE EVENT evnt
ON SCHEDULE 
EVERY 1 SECOND
DO
BEGIN
    CALL proc();
END;
//

DELIMITER ;

SET GLOBAL event_scheduler = 1;

然后运行:

INSERT INTO tbl1 VALUES (UNIX_TIMESTAMP(), 'ex 1');
DO SLEEP(2);
INSERT INTO tbl1 VALUES (UNIX_TIMESTAMP(), 'ex 2');
DO SLEEP(1);
SELECT * FROM tbl2;

将产生以下输出:

+-------------+------+
| i           | v    |
+-------------+------+
| -1348550619 | ex 1 |
| -1348550621 | ex 2 |
+-------------+------+
2 rows in set (0.00 sec)

如果您不想使用EVENT或等待一秒钟左右才能触发,则可以CALL proc()在每条导致TRIGGER触发的命令之后添加。



 类似资料:
  • 本文向大家介绍MySQL 存储过程中执行动态SQL语句的方法,包括了MySQL 存储过程中执行动态SQL语句的方法的使用技巧和注意事项,需要的朋友参考一下

  • 我正在使用带有Sybase ASE数据库的powerbuilder。我在从应用程序执行更新时调用存储过程,但在存储过程中出现错误。我想在存储过程中放置一些打印语句以检查错误是什么。如何查看此打印语句的输出?如何记录存储过程? 提前谢谢Sharmistha

  • 问题内容: 我正在尝试将LIKE关键字与%通配符一起包装参数,但是我不确定如何在不破坏它的情况下将%字符放入语句中。现在我有: 我的.net应用程序中出现SqlException错误,提示“运行时’@search’附近语法不正确。如果删除@search参数周围的%字符,该错误就会消失。 问题答案: %字符必须 在 搜索字符串中… 请注意,以下内容也可以使用,但会引入潜在的SQL注入漏洞…

  • 问题内容: 我正在运行MySQL查询。但是,当从表单输入添加新行时,出现此错误: 从代码: 这个错误是什么意思? 问题答案: INSERT触发器触发时,您无法更改表。INSERT可能会进行一些锁定,这可能导致死锁。同样,从触发器更新表将导致同一触发器在无限递归循环中再次触发。这两个原因都是MySQL阻止您执行此操作的原因。 但是,根据要实现的目标,您可以使用NEW.fieldname甚至旧值(如果

  • 问题内容: 我有一个想要的表:更新该表后,该表的2个字段(标题和描述)会发生变化,并从另一个表中获取价值 这是我的触发器: 我的表: trade_request_type trade_request 错误: 错误1442:无法更新存储函数/触发器中的表’trade_request’,因为调用该存储函数/触发器的语句已使用该表。 这没用!什么是概率? 问题答案: 使用检查null值。 要更改更新后的

  • 问题内容: 我已经研究了几天,感觉就像我在转圈。我具有SQL的基本知识,但是有许多我不了解的领域。 我有一个表,用于存储数据库中所有其他表的名称和字段。 我想编写如下语句,但是无法正常工作: 这可能吗?我开发的应用程序要求用户自定义报告。 问题答案: 如果我正确理解了您要执行的操作,则最好将其作为程序中的两个独立查询来执行。一个查询获取要选择的字段,然后在程序中使用该字段来构建第二个查询,该查询实