Я предполагаю, что я плохо спроектировал свою базу данных, но в настоящее время я озадачен тем фактом, что мне нужно использовать динамический sql в триггере, и это делает mysql несчастным.
Ситуация в том, что у меня естьсоздал базу данных о членстве с несколькими десятками таблиц, главной из которых является таблица 'member' с уникальным первичным ключом 'id'.Существует ряд других таблиц, которые имеют внешние ключи, относящиеся к полю member.id.
Поскольку данные собирались в течение многих лет и с небольшим контролем дублирования, в 'member' есть еще одно полетаблица с именем 'superseded_by', которая содержит идентификатор члена, который заменяет этот.По умолчанию superseded_by установлен как member_id.Любой, чей id superseded_by <> считается дублирующим.
Теперь сложная часть ... когда мы идентифицируем дубли, мы хотим установить поле superseded_by так, чтобы оно указывало на новый первичный элемент и обновите все таблицы с помощью внешних ключей, указывающих на теперь избыточный идентификатор элемента .Я пытался сделать это, используя триггер после обновления ... и затем я попытался быть умным, запрашивая внешние ключи из information_schema и используя динамический sql для их обновления.
Это явно неработа (Код ошибки: 1336 Динамический SQL не разрешен в хранимой функции или триггере).
Я предполагаю, что есть лучший способ для создания схемы / дескриптора, о которых я не думал.
Помогите, пожалуйста ...
КОДЕКС SNIPPET:
-- ---
-- Table 'member'
-- ---
DROP TABLE IF EXISTS member;
CREATE TABLE member (
id INTEGER AUTO_INCREMENT,
superseded_by INTEGER DEFAULT NULL,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE DEFAULT NULL,
gender ENUM('M', 'F') DEFAULT NULL,
mailing_address_id INTEGER DEFAULT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (mailing_address_id) REFERENCES mailing_address (id),
FOREIGN KEY (superseded_by) REFERENCES member (id)
);
DELIMITER $$
CREATE TRIGGER set_superseded_by_on_insert BEFORE INSERT ON member FOR EACH ROW
BEGIN
SET NEW.superseded_by = NEW.id;
END$$
-- Trigger to update other tables (volunteers, donations, presenters, etc.) when member's superseded_by record is updated
-- Assumes the new superseding person exists (they should also not be superseded by anyone themselves)
CREATE TRIGGER adjust_foreign_member_keys_on_superseded_by_update AFTER UPDATE ON member FOR EACH ROW
BEGIN
DECLARE db, tbl, col VARCHAR(64);
DECLARE fk_update_statement VARCHAR(200);
DECLARE no_more_rows BOOLEAN;
DECLARE fks CURSOR FOR SELECT kcu.TABLE_SCHEMA, kcu.TABLE_NAME, kcu.COLUMN_NAME
FROM information_schema.TABLE_CONSTRAINTS tc
JOIN information_schema.KEY_COLUMN_USAGE kcu ON
tc.table_schema = kcu.table_schema AND tc.constraint_name = kcu.constraint_name
WHERE tc.constraint_type='FOREIGN KEY' AND
kcu.REFERENCED_TABLE_NAME = 'member' AND
kcu.REFERENCED_COLUMN_NAME = 'id';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
IF NEW.superseded_by <> OLD.superseded_by THEN
OPEN fks;
SET no_more_rows = FALSE;
update_loop: LOOP
FETCH fks INTO db, tbl, col;
IF no_more_rows THEN
LEAVE update_loop;
END IF;
SET @fk_update_statement = CONCAT("UPDATE ", db, ".", tbl, " SET ", col, " = NEW.superseded_by WHERE ", col, " = NEW.id;");
PREPARE stmt FROM @fk_update_statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE fks;
END IF;
END$$
DELIMITER ;