Mysql

Mysql ,mysql,triggers,schema,dynamic-sql,Mysql,Triggers,Schema,Dynamic Sql,你怎么想?我错过什么了吗 请注意,只有当您使用InnoDB而不是MyISAM时,这才是一个选项 问候,, mysql中的aefxx触发器和存储函数有一些限制,我们不能在这两个函数中都使用动态sql。我希望这能有所帮助。为什么不在应用层处理这个问题呢?我们希望在引擎中完成这一切(这个系统的早期版本在应用程序中做的太多了)。。。我想如果做不到,那就做不到。我仍然有一种唠叨的感觉,觉得我的设计缺少了一些基本的东西。谢谢。。。我考虑过这一点,但我不认为我可以在相关表的外键中引用“被取代的”,因为它在成员

你怎么想?我错过什么了吗

请注意,只有当您使用InnoDB而不是MyISAM时,这才是一个选项

问候,,
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),
);