mysql合并主键

时间:2016-01-20 01:50:53

标签: mysql merge foreign-key-relationship

合并具有外键的记录的最佳方法是什么。 关于“合并记录”有很多主题,但它们主要是选择和分组行。 这显然可以在代码中完成,但安全的数据库解决方案必须更高效。

这是我能想到的最佳解决方案。存储过程中的事务。 关闭外键检查。 更新所有外键。 删除重复记录。

有没有人有更好的方法呢? 或者是否还需要进行其他检查以保持密钥完整性?

数据库示例 - 未经测试

用户'John Doe'(id_user = 2,重复ID = 5)意外地创建了第二个帐户,并希望将所有数据与原始帐户合并。

tbl_users

id_user  | first_name | last_name
1        | John       | Doe
2        | Jane       | Doe
3        | john       | Smith
4        | Jane       | Smith
5        | John       | Doe
6        | Blah       | Meh

tbl_likes

id_user   | apple | orange
2         | 1     | 0
5         | 1     | 1

tbl_random

id_user   | col1   | col2
1         | Aaa    | Bbb
3         | Ccc    | Ddd
5         | Eee    | Fff


DELIMITER $$

CREATE PROCEDURE `tns_merge_user` (IN id_user_old INT, IN id_user_new INT)
    BEGIN

    DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
    DECLARE EXIT HANDLER FOR SQLWARNING ROLLBACK;

    START TRANSACTION;

        # Prevent other queries modifying tables during merge
        LOCK TABLES tbl_users WRITE;
        LOCK TABLES tbl_likes WRITE;
        LOCK TABLES tbl_random WRITE;

        #Disable foreign key checks
        SET FOREIGN_KEY_CHECKS=0;

        # Perform merge queries on related tables
        UPDATE tbl_likes SET id_user = id_user_new;
        UPDATE tbl_random SET id_user = id_user_new;

        # Delete duplicate user record
        DELETE FROM tbl_users WHERE id_user = id_user_old;

        # Re-enable foreign key checks
        SET FOREIGN_KEY_CHECKS=1;
        UNLOCK TABLES;

    COMMIT;
END
$$

1 个答案:

答案 0 :(得分:0)

所以我没有收到任何答案。 我开始做开发测试了。但尚未在生产中使用它。

<强>模式

CREATE TABLE `_test_profile` (
    `id_profile` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `id_profile__merge` int(11) NOT NULL DEFAULT '0',
    `name` varchar(45) COLLATE utf8_unicode_ci NOT NULL,
    PRIMARY KEY (`id_profile`),
    KEY `idx__id_profile__merge` (`id_profile__merge`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `_test_email` (
    `id_email` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `id_profile` int(10) unsigned NOT NULL,
    `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
    `type` enum('primary','postal') COLLATE utf8_unicode_ci NOT NULL,
    PRIMARY KEY (`id_email`),
    KEY `idx_id_profile` (`id_profile`),
    CONSTRAINT `fk__test_email__id_profile` FOREIGN KEY (`id_profile`) REFERENCES `_test_profile` (`id_profile`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `_test_address` (
    `id_address` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `id_profile` int(10) unsigned NOT NULL,
    `address` text COLLATE utf8_unicode_ci NOT NULL,
    PRIMARY KEY (`id_address`),
    KEY `idx_id_profile` (`id_profile`),
    CONSTRAINT `fk__test_address__id_profile` FOREIGN KEY (`id_profile`) REFERENCES `_test_profile` (`id_profile`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

测试插页

INSERT INTO _test_profile(`name`) VALUES
    ('test01'),
    ('test02'),
    ('test03');

INSERT INTO _test_email(id_profile,`type`,`email`) VALUES
    (1,'primary','test01@primary.com'),
    (2,'primary','test02@primary.com'),
    (2,'postal', 'test02@primary.com'),
    (3,'postal','test03@primary.com');

INSERT INTO _test_address(id_profile,`address`) VALUES
    (1,'Address One'),
    (2,'Address Two');

合并交易

需要使用变量包装在存储过程中,确认它是否有效。当我进行适当的测试时,我将使用完整的存储过程代码编辑此答案以供将来参考。

START TRANSACTION;

    # Prevent other queries modifying tables during merge
    LOCK TABLES _test_profile WRITE;

    #Disable foreign key checks
    SET FOREIGN_KEY_CHECKS=0;

    # Modify record to be merged into
    UPDATE _test_profile
    SET id_profile__merge = 1, id_profile = 0
    WHERE id_profile =1;

    SET FOREIGN_KEY_CHECKS=1;

    # Modify record to be merged into
    UPDATE _test_profile
    SET id_profile = 1
    WHERE id_profile =3;

    #Disable foreign key checks
    SET FOREIGN_KEY_CHECKS=0;

    # Delete duplicate user record
    DELETE FROM _test_profile WHERE id_profile = 1;

    # Modify record to be merged into
    UPDATE _test_profile
    SET id_profile = 1, id_profile__merge = 0
    WHERE id_profile__merge =1;

    # Re-enable foreign key checks
    SET FOREIGN_KEY_CHECKS=1;
    UNLOCK TABLES;

COMMIT;

我不会在这个答案中发布未经测试的代码,但是一旦完全正常运行,它将在我的git配置文件中出现。