2011-05-17 75 views
2

我有一个组织和个人之间关联的MyISAM表。每条记录都有一个开始和结束日期。这些记录是在处理大型文本文件时添加的,所以我不做大量的处理和清理,因为它们是为了加速文本解析而添加的。但是,某些记录是冗余的或可能是多余的,因为它们包含重叠的日期范围。由于重叠日期而从MySQL表中删除冗余条目

举例来说,我可能有以下几点:

aff_id aff_e1_id aff_e1_type aff_e2_id aff_e2_type aff_start aff_end 
------ --------- ----------- --------- ----------- ----------- ---------- 
01  172  org   131  indiv  1997-01-22 1998-03-31 
02  172  org   131  indiv  1997-01-22 1999-04-03 
03  100  org   127  indiv  1995-01-02 2000-01-05 
04  100  org   127  indiv  1994-01-24 1999-03-04 

我想要做的是结合是多余的关系记录和修改日期范围,包括任何重叠。例如,前两个记录和最后两个记录可以分别组合,并且修改日期以包含两个日期。

有没有办法在MySQL中完全做到这一点?

编辑: 针对下面的评论,2,3,4,5列需要相同,然后检查日期是否重叠(如果它们完全不重叠,可以让它们单独存在)。

一个存储过程会很棒,但是比使用游标遍历所有记录并一对一地比较它们有更快的方法吗?

+1

你可以在存储过程中做到这一点...你问它是否可以只用一个SQL语句来完成?我认为这很难拉开。分组行的标准是什么 - 第2,3,4和5列是相同的,并且日期重叠? – 2011-05-17 21:03:39

+0

@Paul W - 请参阅编辑以了解您的意见。 – tchaymore 2011-05-17 22:32:36

+0

假设您的数据包含一些范围重叠,一些不重复,而您只想合并重叠的范围,则可以使用使用自连接的更新语句来完成。我开始考虑如何解决这个问题,但不知道艾克的答案是否足够适合你。 – 2011-05-17 22:50:40

回答

1

您可以用一系列删除/更新语句解决这个问题:

  • 删除是完全另一个范围
  • 内的所有范围
  • 更新任何有结束日期> =另一个范围的开始日期的范围
  • 重复(假设您可能有一系列重叠的sa行我的ID),直到你的更新声明不更新任何行

我认为你可以不断更新,并在最后做一次删除,但取决于多少数据和多少重叠,无论如何,这可能并不理想。

DELETE语句:

DELETE sub 
FROM tab AS sub 
INNER JOIN tab AS sup 
    ON sub.aff_e1_type = sup.aff_e1_type 
    AND sub.aff_e2_type = sup.aff_e2_type 
    AND sub.aff_e1_id = sup.aff_e1_id 
    AND sub.aff_e2_id = sup.aff_e2_id 
    AND ((sub.aff_start = sup.aff_start 
    AND sub.aff_end = sup.aff_end 
    AND sub.aff_id < sup.aff_id) 
    OR (sub.aff_start > sup.aff_start 
    AND sub.aff_end <= sup.aff_end 
    AND sub.aff_id <> sup.aff_id) 
    OR (sub.aff_start >= sup.aff_start 
    AND sub.aff_end < sup.aff_end 
    AND sub.aff_id <> sup.aff_id) 
    ) 

更新语句:

UPDATE tab AS row1 
INNER JOIN tab AS row2 
    ON row1.aff_e1_type = row2.aff_e1_type 
    AND row1.aff_e2_type = row2.aff_e2_type 
    AND row1.aff_e1_id = row2.aff_e1_id 
    AND row1.aff_e2_id = row2.aff_e2_id 
    AND row1.aff_end >= row2.aff_start 
    AND row1.aff_start < row2.aff_start 
    AND row1.aff_id <> row2.aff_id 
SET row1.aff_end = row2.aff_end 
1

执行此操作的一种方法是创建表的新副本,使用所需的新分组复制数据,然后重命名表以使用新表替换旧表。如果表格非常大,则使用SELECT ... INTO OUTFILE将数据转储到磁盘可能会更好,然后使用LOAD DATA INFILE将其加载到新表格中。

这是我介绍的第一种方法的一个例子:

CREATE TABLE your_table_new LIKE your_table; 

INSERT INTO your_table_new(aff_id, aff_e1_id, aff_e1_type, aff_e2_id, aff_e2_type, 
    aff_start, aff_end) 
SELECT NULL as aff_id, aff_e1_id, aff_e1_type, aff_e2_id, aff_e2_type, 
    MIN(aff_start), MAX(aff_end) 
FROM your_table 
GROUP BY aff_e1_id, aff_e1_type, aff_e2_id, aff_e2_type; 

RENAME TABLE your_table TO your_table_old, 
    your_table_new TO your_table; 
+0

只要所有的范围都在最小连续的范围内,这将工作。如果您有01/31/2009-03/31/2009和06/30/2009-12/31/2009的范围,此方法将创建01/31/2009-12/31/2009的范围。如果数据排除这种情况发生,这应该起作用。 – 2011-05-17 21:42:22

+0

感谢您的回答,但正如@Paul W指出的那样,并非所有日期范围都是连续的。日期有差距从几个月到几年不等。 – tchaymore 2011-05-17 23:01:13