2016-01-20 5 views
1

Каков наилучший способ слияния записей с внешними ключами. Существует много тем, посвященных «объединению записей», но они в основном выбирают и группируют строки. Это, очевидно, может быть сделано в коде, но безопасное решение для базы данных должно быть более эффективным.mysql merge primary key

Это лучшее решение, о котором я могу думать. Транзакция в хранимой процедуре. Отключить проверки внешнего ключа. Обновить все внешние ключи. Удалить дубликат записи.

У кого-нибудь есть лучший способ сделать это? Или есть ли какие-либо другие проверки, которые также необходимо выполнить для обеспечения целостности ключа?

пример базы данных - непроверенный

пользователя 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 
$$ 

ответ

0

Так что я не получил ny ответы. Я прошел вокруг разработки тестов. Но еще не использовали его в производстве.

схема

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','[email protected]'), 
    (2,'primary','[email protected]'), 
    (2,'postal', '[email protected]'), 
    (3,'postal','[email protected]'); 

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; 

Я не буду размещать непроверенный код в этом ответе, но будет иметь его в своем профиле мерзавца один раз полностью функциональной.