sql >> データベース >  >> RDS >> Mysql

トリガーから呼び出されたストアドプロシージャの動的ステートメントの回避策

    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を使用したくない場合 、または起動するまで1秒ほど待つ場合は、CALL proc()を追加できます。 TRIGGERを引き起こすすべてのコマンドの後 発砲する。




    1. MYSQL-日時から秒

    2. Oracleで月の名前の後の末尾のスペースを削除する方法

    3. Postgresql-データベースをバックアップし、別の所有者に復元しますか?

    4. 動的SQLを使用して複合変数フィールドの値を設定する方法