Mysql
 sql >> база данни >  >> RDS >> Mysql

Динамично изграждане на MySQL код за създаване на тригер

Тъй като не получих никакво определено решение на този въпрос, продължих да създавам опция за доказателство на концепцията (тъй като MySQL по природа не би ви позволил да стартирате SQL код, който създава тригер, използвайки подготвени изявления). Моля, не се колебайте да направите положителен принос.

DELIMITER //
DROP PROCEDURE IF EXISTS createAuditTable//
CREATE PROCEDURE createAuditTable(tblname CHAR(30), sufftxt CHAR(10), pri CHAR(20), filename CHAR(255) )
BEGIN
    SELECT DATABASE() INTO @dbname;
    SET @srctbl = CONCAT(@dbname, ".", tblname);
    SET @destdb = CONCAT(@dbname, "_", sufftxt);
    SET @desttbl = CONCAT(@destdb, ".", tblname);

    SET @str1 = CONCAT( "CREATE DATABASE IF NOT EXISTS ", @destdb);
    PREPARE stmt1 FROM @str1;
    EXECUTE stmt1;
    DEALLOCATE PREPARE stmt1;

    SET @str2 = "SET FOREIGN_KEY_CHECKS=0";
    PREPARE stmt2 FROM @str2;
    EXECUTE stmt2;
    DEALLOCATE PREPARE stmt2;

    SELECT COUNT(*) FROM information_schema.tables WHERE table_name = tblname AND table_schema = @destdb INTO @tblcount;
    IF (@tblcount = 0) THEN 
        SET @str3 = CONCAT("CREATE TABLE ", @desttbl, " LIKE ", @srctbl);
        PREPARE stmt3 FROM @str3;
        EXECUTE stmt3;
        DEALLOCATE PREPARE stmt3;
    END IF;

    SELECT COUNT(*) FROM information_schema.columns WHERE table_name = tblname AND table_schema = @destdb AND column_key = 'PRI' INTO @keycount;

    IF (@keycount <> 0) THEN 
        SET @str4 = CONCAT("ALTER TABLE ", @desttbl, " DROP PRIMARY KEY, ADD INDEX ", pri, " (", pri, ")" );
        PREPARE stmt4 FROM @str4;
        EXECUTE stmt4;
        DEALLOCATE PREPARE stmt4;
    END IF;

SELECT CONCAT( "DELIMITER $$
DROP TRIGGER IF EXISTS ", tblname, "_history_BU$$
CREATE TRIGGER ", tblname, "_history_BU
BEFORE UPDATE ON ", tblname, "
FOR EACH ROW
BEGIN
    INSERT INTO ", @desttbl, " (",
(SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_schema = @dbname AND table_name = tblname), ") ",
    "
    VALUES(", 
(SELECT GROUP_CONCAT('OLD.', column_name) FROM information_schema.columns WHERE table_schema = @dbname AND table_name = tblname),
 ");
END$$
DELIMITER ;"
 ) AS qstr FROM DUAL INTO @triggertxt;

SET @savestr = CONCAT('SELECT ', '"', @triggertxt, '"', " INTO DUMPFILE ", '"', filename, '"');
PREPARE stmt5 FROM @savestr;
EXECUTE stmt5;
DEALLOCATE PREPARE stmt5;


END//
DELIMITER ;  

ЗА ИЗПОЛЗВАНЕ, обадете се на процедурата:

CALL createAuditTable('name_of_table', 'history', 'pri_key_fld', 'path/to/file.sql');

Създава се нова база данни, като се използва името на текущата ви работеща БД, като към нея е добавен суфикс "_history". Таблицата "name_of_table" е създадена в тази нова DB, идентична с оригиналната таблица. Полето "pri_key_fld" (което трябва да бъде първичен/уникален ключ на таблицата "name_of_table") се преобразува в обикновен ключ "INDEX". Целта на това е да се предотвратят уникални нарушения по време на регистриране на множество редове в бъдеще.

След това стартирайте файла, създаден по процедурата:SOURCE 'path/to/file.sql'; (или някакъв алтернативен синтаксис за изпълнение на SQL от този файл)

Няколко предупреждения:В момента можете да предоставите само едно поле за "pri_key_fld". В идеалния случай бихме искали да предоставим "масив", съдържащ всички уникални полета в тази таблица. Понастоящем, ако имате повече от едно уникално поле, уникалните нарушения ще ви попречат да регистрирате повече от един ред. И това не е хубаво!

Отново, очевидно е много тромаво и неефективно да преминете през процеса на създаване на файл на диск, само за да прочетете SQL от същия файл в следващата команда. Една алтернатива, която можете да проучите, за да подобрите, е следната:Стартирайте CALL createAuditTable част от командния ред, хванете изхода като текст, след което изпълнете същото като SQL точно там в командния ред. Опитах това на Windows PowerShell; но изходът беше пълен с литерални низове "\r\n" (представляващи прекъсвания на редове). Нямах време веднага да работя по почистването на този низ, така че сега е в хладилника!

И накрая, о, вие MySQL нинджи, моля, бъдете мили. Не съм професионалист, наистина. Това е просто опит за решаване на практически проблем.

Благодаря.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Броят на колоните не съвпада с броя на стойностите на ред 1

  2. mysqltuner.pl на Windows 2008 сървър r2

  3. COUNT(*) винаги ли връща резултат?

  4. Hibernate-envers хвърля изключение при изтриване на обект с колекция с помощта на CrudRepository

  5. Изявление на MySQL TABLE