Тъй като не получих никакво определено решение на този въпрос, продължих да създавам опция за доказателство на концепцията (тъй като 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 нинджи, моля, бъдете мили. Не съм професионалист, наистина. Това е просто опит за решаване на практически проблем.
Благодаря.