2011-05-17 67 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