Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Obejście dla instrukcji dynamicznych w procedurach składowanych wywoływanych z wyzwalaczy

Nie możesz uruchomić PREPARE /EXECUTE z wnętrza TRIGGER , ale możesz z EVENT (jeśli używasz MySQL w wersji 5.5 lub nowszej).

Oto przykład uruchomienia PREPARE /EXECUTE z 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;

Następnie uruchom to:

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;

wygeneruje ten wynik:

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

Jeśli nie chcesz używać EVENT lub poczekaj sekundę na uruchomienie, możesz dodać CALL proc() po każdym poleceniu, które spowodowałoby TRIGGER strzelać.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PHP/MySQL:przechowywanie i pobieranie UUIDS

  2. sql jak połączyć trzy zapytania z dwóch tabel w jedno zapytanie

  3. Jak używać zmiennych użytkownika MySQL w ADO.NET?

  4. MYSQL nie dodaje informacji do mojej bazy danych

  5. Laravel:pobieranie pojedynczej wartości z zapytania MySQL