MySQL从重复条目中清除表,并在依赖表中重新链接FK

MySQL从重复条目中清除表,并在依赖表中重新链接FK,mysql,foreign-keys,duplicates,duplicate-removal,Mysql,Foreign Keys,Duplicates,Duplicate Removal,这是我的情况:我有两张表,患者和研究 每个表都有自己的PK,使用autoincrement 在我的例子中,pat_id应该是唯一的。它在数据库级别并没有声明为唯一的,因为在某些用途中它可能是非唯一的(它不是自制的系统)。我发现如何配置系统来考虑PATSID是唯一的,但是我现在需要清理重复患者的数据库,并将重复的患者在学习表中遗留给唯一的患者,然后删除重复的患者。 患者表格: CREATE TABLE `patient` ( `pk` BIGINT(20) NOT NULL AUTO_INCR

这是我的情况:我有两张表,
患者
研究

每个表都有自己的PK,使用autoincrement

在我的例子中,pat_id应该是唯一的。它在数据库级别并没有声明为唯一的,因为在某些用途中它可能是非唯一的(它不是自制的系统)。我发现如何配置系统来考虑PATSID是唯一的,但是<强>我现在需要清理重复患者的数据库,并将重复的患者在学习表中遗留给唯一的患者,然后删除重复的患者。

患者
表格:

CREATE TABLE `patient` (
  `pk` BIGINT(20) NOT NULL AUTO_INCREMENT,
  `pat_id` VARCHAR(250) COLLATE latin1_bin DEFAULT NULL,
...
  `pat_name` VARCHAR(250) COLLATE latin1_bin DEFAULT NULL,
...
  `pat_custom1` VARCHAR(250) COLLATE latin1_bin DEFAULT NULL
....
  PRIMARY KEY (`pk`)
)ENGINE=InnoDB;
研究表:

CREATE TABLE `study` (
  `pk` BIGINT(20) NOT NULL AUTO_INCREMENT,
  `patient_fk` BIGINT(20) DEFAULT NULL,
...
  PRIMARY KEY (`pk`),
...
  CONSTRAINT `patient_fk` FOREIGN KEY (`patient_fk`) REFERENCES `patient` (`pk`)
)ENGINE=InnoDB;
我发现了一些类似的问题,但不是完全相同的问题,特别是缺少外键与剩余唯一患者的链接

我就是这样做的

我在
patient
表中重用了一个未使用的字段来标记非重复(N)、重复(X)中的第一个和其他重复的患者(Y)。您还可以为此添加一列(并在使用后将其删除)

以下是我清理数据库时遵循的步骤:

/*1: List duplicated */
select pk,pat_id, t.`pat_id_issuer`, t.`pat_name`, t.pat_custom1
from patient t
where pat_id in (
select pat_id from (
select pat_id, count(*)
from patient 
group by 1
having count(*)>1
) xxx);    

/*2: Delete orphan patients */
delete from patient where pk not in (select patient_fk from study);

/*3: Reset flag for duplicated (or not) patients*/
update patient t set t.`pat_custom1`='N';

/*4: Mark all duplicated */
update patient t set t.`pat_custom1`='Y' 
where pat_id in (
select pat_id from (
select pat_id, count(*)
from patient 
group by 1
having count(*)>1
) xxx) ;

/*5: Unmark the 1st of the duplicated*/
update patient t 
join (select pk from (
select min(pk) as pk, pat_id from patient 
where  pat_custom1='Y'  
group by pat_id
) xxx ) x
on (x.pk=t.pk)
set t.`pat_custom1`='X' 
where  pat_custom1='Y'
  ;

/*6: Verify update is correct*/
select pk, pat_id,pat_custom1  
from `patient` 
where  pat_custom1!='N'
order by pat_id, pat_custom1;

/*7: Verify studies linked to duplicated patient */
select p.* from study s
join patient p on (p.pk=s.patient_fk)
where p.pat_custom1='Y';

/*8: Relink duplicated patients */
update study s
join patient p on (p.pk=s.patient_fk)
set patient_fk = (select pk from patient pp
where pp.pat_id=p.pat_id and pp.pat_custom1='X')
where p.pat_custom1='Y';

/*9: Delete newly orphan patients */
delete from patient where pk not in (select patient_fk from study);

/* 10: reset flag */
update patient t set t.`pat_custom1`=null;

/* 11: Commit changes */
commit;
当然有一种更短的方法,使用更智能(复杂?)的SQL,但我个人更喜欢简单的方法。这也让我可以检查每一步是否符合我的预期