Mysql
你怎么想?我错过什么了吗 请注意,只有当您使用InnoDB而不是MyISAM时,这才是一个选项 问候,,Mysql ,mysql,triggers,schema,dynamic-sql,Mysql,Triggers,Schema,Dynamic Sql,你怎么想?我错过什么了吗 请注意,只有当您使用InnoDB而不是MyISAM时,这才是一个选项 问候,, mysql中的aefxx触发器和存储函数有一些限制,我们不能在这两个函数中都使用动态sql。我希望这能有所帮助。为什么不在应用层处理这个问题呢?我们希望在引擎中完成这一切(这个系统的早期版本在应用程序中做的太多了)。。。我想如果做不到,那就做不到。我仍然有一种唠叨的感觉,觉得我的设计缺少了一些基本的东西。谢谢。。。我考虑过这一点,但我不认为我可以在相关表的外键中引用“被取代的”,因为它在成员
mysql中的aefxx触发器和存储函数有一些限制,我们不能在这两个函数中都使用动态sql。我希望这能有所帮助。为什么不在应用层处理这个问题呢?我们希望在引擎中完成这一切(这个系统的早期版本在应用程序中做的太多了)。。。我想如果做不到,那就做不到。我仍然有一种唠叨的感觉,觉得我的设计缺少了一些基本的东西。谢谢。。。我考虑过这一点,但我不认为我可以在相关表的外键中引用“被取代的”,因为它在成员表中不是唯一的?外键约束中使用的索引不必是唯一的,它只需具有相同的类型(和大小)。MySQL手册说:“InnoDB允许外键引用任何索引列或列组。但是,在引用的表中,必须有一个索引,其中引用的列按相同顺序列为第一列。”备份数据库并尝试一下,我几乎可以肯定这就是您要找的。谢谢。。。碰巧我已经设置了一个日志表来存储更改,所以从成员表中删除重复项没有问题。我想我遗漏了一些东西,因为这不能帮助我更新相关表的fk member_id。我是否仍然需要手动更新这些(在触发器或应用层中)?我的观点是,如果您只是首先防止重复,那么您不需要更新外部成员id,因为member.id字段不会更改。抱歉。。。还是很困惑。问题是,我已经有数百个重复-项目,以确定和消除他们将是一个持续的过程。当我删除它们时,如何有效地更新指向冗余(现在已删除)副本的FK,以指向正确的成员记录?@gidso,我想是我弄糊涂了。如果您现在已经在应用程序中防止重复,并且只是希望清除过去的重复,那么我的回答将不会有多大帮助。我正试图想出一种使用级联约束的方法,但我想不出一种不临时删除member.id唯一性的方法。我建议删除重复项,而不是保留重复项并使用“被取代的_by”字段,但这只是个人偏好,实际上,这无助于解决您的任何问题。@gidso仅供参考,这个关于的问题似乎表明,唯一的选择是使用您已经完成的操作。
-- ---
-- 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 ;
INSERT INTO member_history SELECT NULL, * FROM member WHERE id = ?
UPDATE member SET [...] WHERE id = ?
CREATE TABLE member (
id INTEGER AUTO_INCREMENT,
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),
);
CREATE TABLE member_history (
id INTEGER AUTO_INCREMENT,
member_id INTEGER NOT 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 (member_id) REFERENCES member (id),
);