MysqlPREPAREおよびEXECUTEステートメントは、トリガーによって呼び出されているストアド プロシージャでは使用できません。結果は になりますError Code: 1336. Dynamic SQL is not allowed in stored function or trigger。
これに対するもっともらしい回避策を知っている人はいますか?
MysqlPREPAREおよびEXECUTEステートメントは、トリガーによって呼び出されているストアド プロシージャでは使用できません。結果は になりますError Code: 1336. Dynamic SQL is not allowed in stored function or trigger。
これに対するもっともらしい回避策を知っている人はいますか?
PREPARE/EXECUTEを内部から実行することはできませんがTRIGGER、から実行することはできEVENTます(MySQL 5.5以降を実行している場合)。
:からPREPARE/を実行する例を次に示します。EXECUTEEVENT
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、またはそれが起動するのを1秒ほど待つ場合は、を起動するCALL proc()すべてのコマンドの後にを追加できますTRIGGER。