我有一个表格,描述了对end_customers
表所做的更改。当有人更改并end_customer
我们在end_customers
表格中创建新行并在end_customer_history
表格中添加一行,其中end_customer_parent_id
是旧end_customer
的ID ,end_customer_child_id
是新end_customer
的ID。
最终客户表:
CREATE TABLE `end_customers` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`reference_person` varchar(255) DEFAULT NULL,
`phone_number` varchar(255) NOT NULL,
`email` varchar(255) DEFAULT NULL,
`social_security_number` varchar(255) DEFAULT NULL,
`comment` longtext,
`token` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=101107 DEFAULT CHARSET=utf8;
最终客户历史表:
CREATE TABLE `end_customer_history` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`end_customer_parent_id` bigint(20) NOT NULL,
`end_customer_child_id` bigint(20) NOT NULL,
`user_id` bigint(20) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_end_customer_parent` (`end_customer_parent_id`),
KEY `FK_end_customer_child` (`end_customer_child_id`),
KEY `FK_user` (`user_id`),
CONSTRAINT `end_customer_history_old_ibfk_1` FOREIGN KEY (`end_customer_parent_id`) REFERENCES `end_customers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `end_customer_history_old_ibfk_2` FOREIGN KEY (`end_customer_child_id`) REFERENCES `end_customers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `end_customer_history_old_ibfk_3` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=67 DEFAULT CHARSET=utf8;
我们现在正在重构架构,以便对end_customers
表所做的更改直接编辑行而不是创建新行,并将旧数据的副本放在end_customer_history_new
表中与end_customers
相同的架构。
我需要将所有旧数据迁移到这个新表。
因此,对于我所拥有的每个end_customer
,我需要检查end_customer_history
中的条目是否为end_customer_child_id
(已被修改),然后检查是否也存在该父级在end_customer_history
作为一个孩子,然后检查那个托管父母是否也作为孩子出现在end_customer_history
中,依此类推,直到没有更多行为止。
如何在一个迁移SQL脚本中执行此操作?
答案 0 :(得分:0)
与Oracle不同,MySQL不提供递归查询父子层次结构的功能。如果您事先知道了级别,则可以编写自联接查询(或内部查询)。如果没有,则必须执行单个查询并在应用程序或存储过程中处理resursiveness。
Here是一个查询父子层次结构的示例,如果您已经知道该级别,here是如何在Oracle中执行此操作的示例(供您参考)。
答案 1 :(得分:0)
在我提出的解决方案中,它没有使用任何存储的函数来遍历行,因为我永远无法让它工作。它需要最终版本的最终客户,然后使用我们知道始终相同且唯一的token
加入类似的行。
-- Move data from old end customer history to the new schema
-- May remove some redundant history, this will be ok
-- If an end customer has been changed more than once, all changes will have the same date (latest change) and the same user responsible for change
-- This is also ok
-- Insert the latest version of changed end_customers into new history table
INSERT INTO end_customer_history (name, reference_person, phone_number, email, social_security_number, comment, end_customer_id, user_id, date)
SELECT
ec.name, ec.reference_person, ec.phone_number, ec.email, ec.social_security_number, ec.comment, ech.end_customer_child_id, ech.user_id, ech.date
FROM end_customer_history_old AS ech
JOIN end_customers AS ec ON ec.id = ech.end_customer_parent_id
WHERE ech.end_customer_child_id IN (SELECT end_customer_id FROM orders);
-- Remove all the old data
DROP TABLE end_customer_history_old;
-- Insert all versions of an end_customer based on the latest history, joined on token (always the same)
INSERT INTO end_customer_history (name, reference_person, phone_number, email, social_security_number, comment, end_customer_id, user_id, date)
SELECT
parent.name, parent.reference_person, parent.phone_number, parent.email, parent.social_security_number, parent.comment, ech.end_customer_id, ech.user_id, ech.date
FROM end_customer_history AS ech
JOIN end_customers AS ec ON ec.id = ech.end_customer_id
JOIN end_customers AS parent ON parent.token = ec.token AND parent.id <> ec.id;
-- This unfortunately creates duplicates of some rows, so it looks like changes have been made multiple times (with no new data)
-- Create a temporary table that copies over unique rows from end_customer_history
CREATE TABLE temp AS
SELECT * FROM end_customer_history
GROUP BY
name, reference_person, phone_number, email, social_security_number, comment, end_customer_id, user_id, date;
-- Clear the end_customer_history table all together
TRUNCATE TABLE end_customer_history;
-- Copy over filtered unique history rows
INSERT INTO end_customer_history (name, reference_person, phone_number, email, social_security_number, comment, end_customer_id, user_id, date)
SELECT
name, reference_person, phone_number, email, social_security_number, comment, end_customer_id, user_id, date
FROM temp;
-- Remove temporary table
DROP TABLE temp;