Trợ giúp về tìm dữ liệu trùng trong excel (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

PHP:
Private Function RemoveItem(SrcRng As Range, Criteria As Range) As Range
  Dim tmpRng As Range
  On Error GoTo ExitFunc
  SrcRng.AdvancedFilter 1, Criteria
  Set tmpRng = SrcRng.SpecialCells(12)
  SrcRng.Parent.ShowAllData
  tmpRng.EntireRow.Hidden = True
  Set tmpRng = SrcRng.SpecialCells(12)
  SrcRng.EntireRow.Hidden = False
  Set RemoveItem = tmpRng
ExitFunc:
End Function


PHP:
 Sub Main()
  Dim Src1 As Range, Crit1 As Range, Src2 As Range, Crit2 As Range
  Dim Del1 As Range, Del2 As Range
  On Error GoTo ExitSub
  Application.ScreenUpdating = False
  Set Src1 = Range([A1], [A65536].End(xlUp))
  Set Crit1 = Range("IU1:IU2")
  Set Src2 = Range([B1], [B65536].End(xlUp))
  Set Crit2 = Range("IV1:IV2")
  Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
  Crit2(2) = "=COUNTIF(" & Src1.Address & ", " & Src2(2, 1).Address(0, 0) & ")=0"
  Set Del1 = RemoveItem(Src1, Crit1)
  Set Del2 = RemoveItem(Src2, Crit2)
  Del1.Delete 2: Del2.Delete 2
ExitSub:
  Crit1.ClearContents: Crit2.ClearContents
  Application.ScreenUpdating = True
End Sub

Cho em được hỏi Delete 2 trong Code trên (Del1.Delete 2: Del2.Delete 2) có nghĩa là gì ah?
 
PHP:
Private Function RemoveItem(SrcRng As Range, Criteria As Range) As Range
  Dim tmpRng As Range
  On Error GoTo ExitFunc
  SrcRng.AdvancedFilter 1, Criteria
  Set tmpRng = SrcRng.SpecialCells(12)
  SrcRng.Parent.ShowAllData
  tmpRng.EntireRow.Hidden = True
  Set tmpRng = SrcRng.SpecialCells(12)
  SrcRng.EntireRow.Hidden = False
  Set RemoveItem = tmpRng
ExitFunc:
End Function


PHP:
 Sub Main()
  Dim Src1 As Range, Crit1 As Range, Src2 As Range, Crit2 As Range
  Dim Del1 As Range, Del2 As Range
  On Error GoTo ExitSub
  Application.ScreenUpdating = False
  Set Src1 = Range([A1], [A65536].End(xlUp))
  Set Crit1 = Range("IU1:IU2")
  Set Src2 = Range([B1], [B65536].End(xlUp))
  Set Crit2 = Range("IV1:IV2")
  Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
  Crit2(2) = "=COUNTIF(" & Src1.Address & ", " & Src2(2, 1).Address(0, 0) & ")=0"
  Set Del1 = RemoveItem(Src1, Crit1)
  Set Del2 = RemoveItem(Src2, Crit2)
  Del1.Delete 2: Del2.Delete 2
ExitSub:
  Crit1.ClearContents: Crit2.ClearContents
  Application.ScreenUpdating = True
End Sub

Cho em được hỏi Delete 2 trong Code trên (Del1.Delete 2: Del2.Delete 2) có nghĩa là gì ah?
Delete 2 tương đương với thao tác quét chọn vùng, click phải chọn Delete\Shift cells up
 
Em thử thử mấy ví dụ quả Delete\Shift cells up Delete\Shift cells left chẳng khác nhau chút nào, vậy hai thằng này nó khác nhau trong TH nào hả thày?
 
Em thử thử mấy ví dụ quả Delete\Shift cells up Delete\Shift cells left chẳng khác nhau chút nào, vậy hai thằng này nó khác nhau trong TH nào hả thày?

Khác chứ... Ví dụ bạn quét chọn vùng G6:G12 thì
- Shift cells left sẽ xóa G6:G12 đồng thời đôn thằng H6:H12 sang vị trí của G6:G12
- Shift cells up sẽ xóa G6:G12 đồng thời đôn thằng G13 lên tại vị trí của G6
Đại khái mấy thằng Shift cell này ngoài xóa ra, sẽ dồn các cell bên phải lấp đầy vị trí vừa xóa (nếu là shift cells left) hoặc sẽ dồn các cell bên dưới lấp đầy vị trí vừa xóa (nếu là shift cell up)
 
Tại em NGU quá, đi thử nghiệm với 2 cột duy nhất (mà lại thử nghiệm Cell cuối) --> không nhận ra.

Cũng nhờ đọc các bài của thày, được thày trực tiếp hướng dẫn; bây giờ em đã phần nào đoán ra được các chỉ số viết tắt của các phương thức Delete, SpecialCells, Advanced Filter...rồi, các chỉ số viết tắt như 1, 2, 3, 4, 23.. thường là số thứ tự (hoặc phản ánh số tổng) của tùy chọn.
 
Em làm thử bài toán nhỏ: Yêu cầu xóa những dòng nào mà giá trị cột A đã tồn tại ở cột B.

PHP:
Sub Macro1()
    Dim Src1 As Range, Crit1 As Range, Src2 As Range, tmpRng As Range
    Dim RemoveItem As Range
    Set Src1 = Range([A1], [A65536].End(xlUp))
    Set Src2 = Range([B1], [B65536].End(xlUp))
    Set Crit1 = Range("D1:D2")
    Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
    Src1.AdvancedFilter 1, CriteriaRange:=Range("D1:D2")
    Set tmpRng = Src1.SpecialCells(12)
    Src1.Parent.ShowAllData
    tmpRng.EntireRow.Hidden = True
    Set tmpRng = Src1.SpecialCells(12)
    tmpRng.EntireRow.Hidden = False
    Set RemoveItem = tmpRng
    RemoveItem.Delete 2
End Sub

Sau khi làm xong Code chạy đúng nhưng nó cứ bị ẩn một số dòng đi, vậy ta cần thêm dòng lệnh nào để nó hiện ra tất cả toàn bộ dữ liệu sau khi xóa.
 

File đính kèm

Em làm thử bài toán nhỏ: Yêu cầu xóa những dòng nào mà giá trị cột A đã tồn tại ở cột B.

Mã:
Sub Macro1()
    Dim Src1 As Range, Crit1 As Range, Src2 As Range, tmpRng As Range
    Dim RemoveItem As Range
    Set Src1 = Range([A1], [A65536].End(xlUp))
    Set Src2 = Range([B1], [B65536].End(xlUp))
    Set Crit1 = Range("D1:D2")
    Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
    Src1.AdvancedFilter 1, CriteriaRange:=Range("D1:D2")
    Set tmpRng = Src1.SpecialCells(12)
    Src1.Parent.ShowAllData
    tmpRng.EntireRow.Hidden = True
    Set tmpRng = Src1.SpecialCells(12)
    [COLOR=#ff0000][B]tmpRng.EntireRow.Hidden = False[/B][/COLOR]
    Set RemoveItem = tmpRng
    RemoveItem.Delete 2
End Sub

Sau khi làm xong Code chạy đúng nhưng nó cứ bị ẩn một số dòng đi, vậy ta cần thêm dòng lệnh nào để nó hiện ra tất cả toàn bộ dữ liệu sau khi xóa.
Sai chổ màu đỏ:
Ở trên đã cho tmpRng là các cell không ẩn trong vùng Src1
Giờ bạn lại cho tmpRng.EntireRow.Hidden = False cũng bằng không (thực chất nó vẫn đang hiện mà)
Chổ màu đỏ ấy sửa thành Src1.EntireRow.Hidden = False là xong chuyện
-----------------
Lưu ý: Cẩn thận với code này! Hãy mường tượng tình huống người ta chạy code 2 lần trở lên thì chuyện gì xãy ra nhé
 
Lần chỉnh sửa cuối:
Nếu chạy 2 lần trở lên thì lần 2 nó sẽ báo lỗi (vì các dòng trùng đã bị xóa), vậy ta phải bẫy lỗi Code này như thế nào ah
PHP:
Sub Macro1()
    Dim Src1 As Range, Crit1 As Range, Src2 As Range, tmpRng As Range
    Dim RemoveItem As Range
    Set Src1 = Range([A1], [A65536].End(xlUp))
    Set Src2 = Range([B1], [B65536].End(xlUp))
    Set Crit1 = Range("D1:D2")
    Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
    Src1.AdvancedFilter 1, CriteriaRange:=Range("D1:D2")
    Set tmpRng = Src1.SpecialCells(12)
    Src1.Parent.ShowAllData
    tmpRng.EntireRow.Hidden = True
    Set tmpRng = Src1.SpecialCells(12)
    Src1.EntireRow.Hidden = False
    Set RemoveItem = tmpRng
    RemoveItem.Delete 2
End Sub
 
Nếu chạy 2 lần trở lên thì lần 2 nó sẽ báo lỗi (vì các dòng trùng đã bị xóa), vậy ta phải bẫy lỗi Code này như thế nào ah
PHP:
Sub Macro1()
    Dim Src1 As Range, Crit1 As Range, Src2 As Range, tmpRng As Range
    Dim RemoveItem As Range
    Set Src1 = Range([A1], [A65536].End(xlUp))
    Set Src2 = Range([B1], [B65536].End(xlUp))
    Set Crit1 = Range("D1:D2")
    Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
    Src1.AdvancedFilter 1, CriteriaRange:=Range("D1:D2")
    Set tmpRng = Src1.SpecialCells(12)
    Src1.Parent.ShowAllData
    tmpRng.EntireRow.Hidden = True
    Set tmpRng = Src1.SpecialCells(12)
    Src1.EntireRow.Hidden = False
    Set RemoveItem = tmpRng
    RemoveItem.Delete 2
End Sub
Đơn giản nhất là:
On Error Goto ExitSub
Mã:
Sub Macro1()
    Dim Src1 As Range, Crit1 As Range, Src2 As Range, tmpRng As Range
    Dim RemoveItem As Range
    [COLOR=#ff0000][B]On Error Goto ExitSub[/B][/COLOR]
    Set Src1 = Range([A1], [A65536].End(xlUp))
    Set Src2 = Range([B1], [B65536].End(xlUp))
    Set Crit1 = Range("D1:D2")
    Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
    Src1.AdvancedFilter 1, CriteriaRange:=Range("D1:D2")
    Set tmpRng = Src1.SpecialCells(12)
    Src1.Parent.ShowAllData
    tmpRng.EntireRow.Hidden = True
    Set tmpRng = Src1.SpecialCells(12)
    Src1.EntireRow.Hidden = False
    Set RemoveItem = tmpRng
    RemoveItem.Delete 2
[COLOR=#ff0000][B]ExitSub:[/B][/COLOR]
End Sub
Tuy nhiên tôi vẫn ủng hộ cách tìm hiểu lỗi đến nơi đến chốn (tức phải hiểu lỗi xuất hiện từ đâu)
Để ý sẽ thấy có 2 trường hợp mà lỗi có thể xuất hiện:
- Thứ nhất: Advanced Filter không lọc được bất cứ thứ gì, tức toàn bộ cột A đều trùng cột B ---> khi ấy nó sẽ "quét sạch cột A trong lần lọc đầu (chỉ chừa lại tiêu đề) ---> Dẫn đến lần 2 bị lỗi
- Thứ hai: Kết quả của Advanced Filter chính = toàn bộ các phần tử cột A, tức không có cell nào trong cột A trùng với cột B ---> Dẫn đến không có dòng nào ẩn và đoạn code Src1.Parent.ShowAllData bị lỗi ngay lập tức ---> Trong trường hợp này thì Src1.Count = tmpRng.Count, đúng không?
------------
Vậy để tránh lỗi triệt để cho cả 2 trường hợp, tôi làm như sau
PHP:
Sub Macro1()
  Dim Src1 As Range, Crit1 As Range, Src2 As Range, tmpRng As Range
  Set Src1 = Range([A1], [A65536].End(xlUp))
  Set Src2 = Range([B1], [B65536].End(xlUp))
  Set Crit1 = Range("D1:D2")
  Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
  If Src1.Count > 1 Then ''<--- phòng trường hợp Src1 chỉ có 1 cell
    Src1.AdvancedFilter 1, CriteriaRange:=Range("D1:D2")
    Set tmpRng = Src1.SpecialCells(12)
    If tmpRng.Count <> Src1.Count Then ''<--- phòng trường hợp toàn bộ cột A đều thỏa mản điều kiện nên không có dòng nào bị ẩn
      Src1.Parent.ShowAllData
      tmpRng.EntireRow.Hidden = True
      Set tmpRng = Src1.SpecialCells(12)
      Src1.EntireRow.Hidden = False
      tmpRng.Delete 2
    End If
  End If
End Sub
Thậm chí là không cần đến bất kỳ câu bẫy lỗi nào luôn
 
Lần chỉnh sửa cuối:
PHP:
Sub Macro1()
  Dim Src1 As Range, Crit1 As Range, Src2 As Range, tmpRng As Range
  Set Src1 = Range([A1], [A65536].End(xlUp))
  Set Src2 = Range([B1], [B65536].End(xlUp))
  Set Crit1 = Range("D1:D2")
  Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
  If Src1.Count > 1 Then ''<--- phòng trường hợp Src1 chỉ có 1 cell
    Src1.AdvancedFilter 1, CriteriaRange:=Range("D1:D2")
    Set tmpRng = Src1.SpecialCells(12)
    If tmpRng.Count <> Src1.Count Then ''<--- phòng trường hợp toàn bộ cột A đều thỏa mản điều kiện nên không có dòng nào bị ẩn
      Src1.Parent.ShowAllData
      tmpRng.EntireRow.Hidden = True
      Set tmpRng = Src1.SpecialCells(12)
      Src1.EntireRow.Hidden = False
      tmpRng.Delete 2
    End If
  End If
End Sub
Rất tuyệt vời, Code của thày bao giờ cũng rất chặt chẽ về cú pháp, cảm ơn thày rất nhiều.
 
Lần chỉnh sửa cuối:
Em thử thay đoạn
PHP:
Src1.EntireRow.Hidden = False
bằng
PHP:
Src1.Parent.ShowAllData

Cụ thể toàn bộ Code sau khi thay sẽ như thế này
PHP:
Sub Macro1()
  Dim Src1 As Range, Crit1 As Range, Src2 As Range, tmpRng As Range
  Set Src1 = Range([A1], [A65536].End(xlUp))
  Set Src2 = Range([B1], [B65536].End(xlUp))
  Set Crit1 = Range("D1:D2")
  Crit1(2) = "=COUNTIF(" & Src2.Address & ", " & Src1(2, 1).Address(0, 0) & ")=0"
  If Src1.Count > 1 Then ''<--- phòng trường hợp Src1 chỉ có 1 cell
    Src1.AdvancedFilter 1, CriteriaRange:=Crit1
    Set tmpRng = Src1.SpecialCells(12)
    If tmpRng.Count <> Src1.Count Then ''<--- phòng trường hợp toàn bộ cột A đều thỏa mản điều kiện nên không có dòng nào bị ẩn
      Src1.Parent.ShowAllData
      tmpRng.EntireRow.Hidden = True
      Set tmpRng = Src1.SpecialCells(12)
      Src1.Parent.ShowAllData
      tmpRng.Delete 2
    End If
  End If
End Sub
thì báo lỗi, em nghĩ nó tương đương chứ nhỉ?
 
Bạn xem File đúng ý bạn khống nhé

Chào bác! Em đã xem file của bác và muốn nhờ các bác giúp như sau:
Em có file gồm ~60.000 dòng. Em muốn tô màu nền cho những ô trùng nhau về giá trị trong 1 cột (Cột A). Em đã dùng Countif trong Conditional Formating nhưng nó làm file chạy rất chậm. Em nghe nói VBA giải quyết ngon ơ mà không làm máy chậm, vì vậy nhờ các bác giúp. Lưu ý ô A2=0000007 và A3=7 cũng coi là trùng.
Ngoài ra các bác chỉ cách đếm số lượng các cặp số trùng ấy (cho hiện ở ô C1 chẳng hạn)
Xin cảm ơn trước
 
Chúc mừng năm mới!


Làm giúp bạn theo tin nhắn hôm qua, tết mà cũng phải làm.

MinhKhai đã viết:
Em vào GPE và search được chủ đề về dữ liệu trùng mà bác đăng bài.

Em có gửi nhờ ở vài topic khác nhưng chưa được giúp đỡ. Mong bác giúp đỡ

Em có file dữ liệu như file gửi kèm (thực tế có khoảng ~65.000 dòng). Việc dò tìm các mã dùng bằng CF hoặc Validation (hàm Countif) khiến file chạy rất chậm. Thực tế chưa có hàm này file đã chạy chậm rồi. Em

Em nghe nói VBA sẽ chạy nhanh hơn, nên nhờ bác tạo lập đoạn code để dò tìm các mã trùng (Cột A).
Yêu cầu chính: Mỗi khi mở file hoặc ngay khi nhập mã nếu trùng sẽ xuất hiện thông báo mã trùng. (Vẫn cho phép nhập trùng nhưng tô nền màu của ô trùng nhau)
Yêu cầu phụ: Tại 1 ô cho hiện thông báo số cặp ô trùng.

Cảm ơn bác nhiều

File đính kèm: https://dl.dropbox.com/s/p6yjh7gwa7b0pxd/CG 2012.rar?dl=1


Code trong module
Mã:
 Public Dic
Sub Test()
    Dim arrKH, tr, k, Ma
    Set Dic = CreateObject("Scripting.Dictionary")
    With ActiveSheet
        arrKH = .Range(.[A3], .[A65536].End(xlUp)).Value
    End With
    For k = 1 To UBound(arrKH, 1)
        tr = 1
        Ma = Format(arrKH(k, 1), "0000000")
        If Ma <> "" Then
            If Not Dic.exists(Ma) Then
                Dic.Add Ma, tr
            Else
                tr = Dic.Item(Ma)
                Dic.Item(Ma) = tr + 1
            End If
        End If
    Next
thoat:
    Application.EnableEvents = True
End Sub

Code trong sheet
Mã:
Private Sub Worksheet_Change(ByVal Target As Range)
    Dim Kh As Range, i As Long, tr
    Application.EnableEvents = False
    'On Error GoTo thoat
    If Target.Column = 1 Then
        Call Test
        Target.ClearComments
        For i = 1 To Target.Count
            Set Kh = Target(i)
            If Kh.Interior.ColorIndex = 40 Then Kh.Interior.ColorIndex = xlNone
            If Kh <> "" Then
                tr = Dic.Item(Kh.Text)
                If tr > 1 Then
                    With Kh
                        .AddComment
                        .Comment.Visible = False
                        .Comment.Text Text:=Kh.Text & " = " & tr & " lan"
                        .Interior.ColorIndex = 40
                        '  .Comment.Shape.ScaleHeight 0.22, msoFalse, msoScaleFromTopLeft
                    End With
                End If
            End If
        Next
    End If
thoat:
    Set Dic = CreateObject("Scripting.Dictionary")
    Application.EnableEvents = True
End Sub
 
Lần chỉnh sửa cuối:
Chúc mừng năm mới!


Làm giúp bạn theo tin nhắn hôm qua, tết mà cũng phải làm.

Chân thành cảm ơn bác đã nhiệt tình giúp đỡ.
Em đã thử cho chạy code và thấy rất như mong muốn. Tuy nhiên nếu bác không bận cho em hỏi thêm 2 câu hỏi để bác xử lý
1. Khi đặt Code vào file, các ô nhập mới sẽ báo nếu có trùng, tuy nhiên những ô đang có giá trị trùng lặp sẵn trong cột thì không hiển thị
2. Do dữ liệu dài nên em thường freeze pane và đưa các kết quả lên những dòng đầu. Yêu cầu phụ của em là muốn hiển thị tổng số các ô (hoặc nhóm ô) trùng nhau trong cột (Vd: Cột có 20 mã số trong đó có 2 cặp số trùng nhau...)

Thêm lần nữa cảm ơn bác. Chúc bác năm mới mạnh khỏe
 
Trước mắt bạn có thể đánh dấu các ô trùng bằng cách copy nguyên cột rồi dán value xuống lại ngay tại vị trí đó. Còn mỗi lần nhập xong một ô mà muốn code kiểm tra lại 65000 dòng thì e rằng có khi phải chờ code ... chạy.
 
Lần chỉnh sửa cuối:
Web KT

Bài viết mới nhất

Back
Top Bottom