2016-09-01 74 views
1

我有一個刪除重複項的宏(基於列A)。它排序P中上升然後刪除整個行是一個重複的,所以我可以確保的是,宏只刪除最早的行(列P =日期):刪除重複項(海量數據,非常慢)

Sub SortAndRemoveDUBS() 

Dim Rng As Range 
Dim LastRow As Long 
Dim i As Long 

Application.ScreenUpdating = False 

LastRow = Cells(Rows.Count, "B").End(xlUp).Row 

Set Rng = Range("A4:P" & LastRow) 

With Rng 
    .Sort Key1:=Range("A4"), Order1:=xlAscending, key2:=Range("P4"), order2:=xlDescending, _ 
     Header:=xlYes, OrderCustom:=1, MatchCase:=False, _ 
     Orientation:=xlTopToBottom 
End With 

For i = LastRow To 2 Step -1 
    If WorksheetFunction.CountIf(Range(Cells(2, "A"), Cells(i, "A")), Cells(i, "A")) > 1 Then 
     Rows(i).Delete 
    End If 
Next i 

Application.ScreenUpdating = True 

End Sub 

但宏是很慢的。有沒有辦法加快速度?我認爲這是因爲他刪除了每一個重複的一個。

+0

如果你有很多的公式加上'Application.Calculation = xlCalculationManual'頂端,只記得設置回用'Application.Calculation = xlCalculationAutomatic' –

+0

有在片沒有公式。 – Bluesector

+0

@Bluesector爲什麼列P是日期,列是你的ID? 爲什麼在你排序後,你不檢查單元格(i,1)=單元格(i-1,1)?!?! ? 我試了兩種方式,你和我的50K的記錄。你的時間是00:01:21,我的00:00:23。 PS:可以是我缺少的東西,請解釋一下 – Fabrizio

回答

2

可以通過在一個這樣的數組收集所有的行號在年底做刪除操作:

(未測試)

Dim arr() as variant ,cnt As LOng 
cnt=0 

For i = LastRow To 2 Step -1 
    If WorksheetFunction.CountIf(Range(Cells(2, "A"), Cells(i, "A")), Cells(i, "A")) > 1 Then 
     Redim Preserve arr(cnt) 
     arr(cnt) = i 
     cnt=cnt+1 
    End If 
Next i 

If Len(join(arr))> 0 then ActiveSheet.Range("A" & Join(arr, ",A")).EntireRow.Delete 
+0

我得到一個編譯錯誤:期望的數組。嘗試谷歌它,但無法找到我的錯誤在這裏......'ReDim保存arr(cnt)' – Bluesector

+0

編輯再試一次 – newguy

+0

工作了一會兒......現在我得到一個運行時錯誤'1004':應用程序定義或者對象定義的錯誤'ActiveSheet.Range(「A」&Join(arr,「,A」))。EntireRow.Delete' – Bluesector

0

類似@法布里奇奧的評論,我發現這一個工作得很好。

Sub Delete_row() 

Dim a As Variant 

    ' selects all data in columns A to P and sorts by data in column P from oldest to newest 
    Columns("A:P").Select 
    ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear 
    ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range(_ 
     "P:P"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _ 
     xlSortNormal 
     With ActiveWorkbook.Worksheets("Sheet1").Sort 
     .SetRange Range("A:P") 
     .Header = xlGuess 
     .MatchCase = False 
     .Orientation = xlTopToBottom 
     .SortMethod = xlPinYin 
     .Apply 
    End With 

    a = 2 

    While Cells(a, 16) <> vbNullString 

'  Marks column Q with a value of 1 for every cell in P 
'  that has the same date as the previous cell 

     If Cells(a, 16) = Cells(a - 1, 16) Then 
      Cells(a, 17) = 1 
     End If 

     a = a + 1 
    Wend 

'  Filters column Q for the value of 1 

     Columns("A:Q").AutoFilter 
     ActiveSheet.Range("$A:Q").AutoFilter Field:=17, Criteria1:="<>" 

     Range(Selection, Selection.End(xlToRight)).Select 
     Range(Selection, Selection.End(xlDown)).Select 
     Selection.ClearContents 

     ActiveSheet.Range("$A:Q").AutoFilter Field:=17 

     Columns("A:P").Select 
     ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear 
     ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range(_ 
      "P:P"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _ 
      xlSortNormal 
      With ActiveWorkbook.Worksheets("Sheet1").Sort 
      .SetRange Range("A:P") 
      .Header = xlGuess 
      .MatchCase = False 
      .Orientation = xlTopToBottom 
      .SortMethod = xlPinYin 
      .Apply 
     End With 

     Columns("Q:Q").ClearContents 

End Sub 

我已經更改了代碼以增加宏的速度。使用Excel 2010(32位,第二代i5和8GB內存)運行約30-35秒。

+0

謝謝!呃仍然真的很慢...我的電腦不是最好的.Newguy的解決方案是一種更快的方式,然後我得到了那個奇怪的錯誤。 – Bluesector

+0

@Bluesector添加了新的代碼。這應該會更好 – Clauric

2

CountIf很慢,一次刪除一行很慢。嘗試使用字典(您將需要設置對Microsoft腳本運行時的引用)。

Sub SortAndRemoveDUBS() 

Dim Rng As Range 
Dim LastRow As Long 
Dim i As Long 

Application.ScreenUpdating = False 

LastRow = Cells(Rows.Count, "B").End(xlUp).Row 

Set Rng = Range("A4:P" & LastRow) 

With Rng 
    .Sort Key1:=Range("A4"), Order1:=xlAscending, key2:=Range("P4"), order2:=xlDescending, _ 
     Header:=xlYes, OrderCustom:=1, MatchCase:=False, _ 
     Orientation:=xlTopToBottom 
End With 

Dim dict As New Dictionary 
Dim r As Range 

For i = 2 To LastRow 
    If dict.Exists(Cells(i, "A").Value) Then 
     If r Is Nothing Then 
      Set r = Cells(i, "A") 
     Else 
      Set r = Union(r, Cells(i, "A")) 
     End If 
    Else 
     dict.Add Cells(i, "A").Value, 1 
    End If 
Next i 

r.EntireRow.Delete 
Application.ScreenUpdating = True 

End Sub