Nhờ tìm lỗi code không delete các dòng theo điều kiện

Liên hệ QC

AnhThu-1976

Thành viên tích cực
Tham gia
17/10/14
Bài viết
1,052
Được thích
168
Em chào các anh/ chị thành viên
Em có viết code như sau
Mã:
Sub Xoa()
Dim Lr As Long, i As Long
    Sheets("TH").Select
    Lr = ActiveSheet.Range("E" & Rows.Count).End(xlUp).Row
    
    For i = 9 To Lr
    If Cells(i, 5) = "Anh Thu" Then Cells(i, 5).EntireRow.Delete
    If Cells(i, 5) = "Anh Dung" Then Cells(i, 5).EntireRow.Delete
    If Cells(i, 5) = "Anh Hung" Then Cells(i, 5).EntireRow.Delete
    
    Next i

End Sub
Tại cột E của sheet TH, nếu ô nào có cụm từ Anh Thu hoặc Anh Dung hoặc Anh Hung thì delete dòng tương ứng, cho em hỏi 2 ý như sau

1/ Không biết code sai chổ nào, mà nó không delete hết các dòng theo điều kiện trên (đúng lý là nó delete các dòng tô chữ đỏ, nhưng nó delete không hết)

2/ Code trên duyệt từng ô từ dưới lên trên nên nó chạy chậm (nếu Data khoảng 5~ 7 ngàn dòng)

Nên anh/chị có code nào cho nó chạy nhanh hơn không thì giúp em
Em cảm ơn!
 

File đính kèm

  • XoaDong.xlsm
    15 KB · Đọc: 9
Em chào các anh/ chị thành viên
Em có viết code như sau
Mã:
Sub Xoa()
Dim Lr As Long, i As Long
    Sheets("TH").Select
    Lr = ActiveSheet.Range("E" & Rows.Count).End(xlUp).Row
  
    For i = 9 To Lr
    If Cells(i, 5) = "Anh Thu" Then Cells(i, 5).EntireRow.Delete
    If Cells(i, 5) = "Anh Dung" Then Cells(i, 5).EntireRow.Delete
    If Cells(i, 5) = "Anh Hung" Then Cells(i, 5).EntireRow.Delete
  
    Next i

End Sub
Tại cột E của sheet TH, nếu ô nào có cụm từ Anh Thu hoặc Anh Dung hoặc Anh Hung thì delete dòng tương ứng, cho em hỏi 2 ý như sau

1/ Không biết code sai chổ nào, mà nó không delete hết các dòng theo điều kiện trên (đúng lý là nó delete các dòng tô chữ đỏ, nhưng nó delete không hết)

2/ Code trên duyệt từng ô từ dưới lên trên nên nó chạy chậm (nếu Data khoảng 5~ 7 ngàn dòng)

Nên anh/chị có code nào cho nó chạy nhanh hơn không thì giúp em
Em cảm ơn!
bạn cho chạy từ for i=lr to 9 sẽ hết lỗi
 
Upvote 0
Upvote 0
bạn cho chạy từ for i=lr to 9 sẽ hết lỗi
tôi đổi ngược lại thì nó không chạy luôn đó bạn (nhưng thấy nó ngược ngược thì phải)
Bài đã được tự động gộp:

Bạn xem bổ sung việc kiểm tra Lr, nếu Lr > 9 thì mới thực thi
Mã:
If Lr > 9 then
        For i = 9 To Lr
sau khi chạy thì vẫn ra kết quả như bài #1, bạn thử xem nhé!
Bài đã được tự động gộp:

Muốn nhanh thì ghi kết quả sang 1 mảng khác. Còn duyệt từng dòng thế kia thì có thể tìm hiểu union để tăng tốc độ hơn 1 chút
1/ nhờ anh anh làm mẫu để em áp dụng
2/ Anh xem giúp, tại sao code trên nó chạy ra kết quả sai
Cảm ơn anh!
 
Upvote 0
Em chào các anh/ chị thành viên
Em có viết code như sau
Mã:
Sub Xoa()
Dim Lr As Long, i As Long
    Sheets("TH").Select
    Lr = ActiveSheet.Range("E" & Rows.Count).End(xlUp).Row
   
    For i = 9 To Lr
    If Cells(i, 5) = "Anh Thu" Then Cells(i, 5).EntireRow.Delete
    If Cells(i, 5) = "Anh Dung" Then Cells(i, 5).EntireRow.Delete
    If Cells(i, 5) = "Anh Hung" Then Cells(i, 5).EntireRow.Delete
   
    Next i

End Sub
Tại cột E của sheet TH, nếu ô nào có cụm từ Anh Thu hoặc Anh Dung hoặc Anh Hung thì delete dòng tương ứng, cho em hỏi 2 ý như sau

1/ Không biết code sai chổ nào, mà nó không delete hết các dòng theo điều kiện trên (đúng lý là nó delete các dòng tô chữ đỏ, nhưng nó delete không hết)

2/ Code trên duyệt từng ô từ dưới lên trên nên nó chạy chậm (nếu Data khoảng 5~ 7 ngàn dòng)

Nên anh/chị có code nào cho nó chạy nhanh hơn không thì giúp em
Em cảm ơn!
Tham khảo code đã sửa. (làm theo gọi ý của @BuiQuangThuan )
Mã:
Sub Xoa()
Dim Lr As Long, i As Long, Rng As Range
    Sheets("TH").Select
    Lr = ActiveSheet.Range("E" & Rows.Count).End(xlUp).Row
    If Lr <= 8 Then Exit Sub
    For i = 9 To Lr
        If Cells(i, 5) = "Anh Thu" Or Cells(i, 5) = "Anh Dung" Or Cells(i, 5) = "Anh Hung" Then
            If Rng Is Nothing Then
                Set Rng = Cells(i, 5)
            Else
                Set Rng = Union(Rng, Cells(i, 5))
            End If
        End If
    Next i
    ' Rng.Select
    Rng.EntireRow.Delete
End Sub
 
Upvote 0
2/ Anh xem giúp, tại sao code trên nó chạy ra kết quả sai
Cảm ơn anh!
Còn đoạn này thì bạn cứ hình dung như này:
Nếu i = 9 thỏa mãn thì nó xóa dòng số 9 đi. Lúc này dòng số 10 nó sẽ là dòng số 9. Và i tăng lên 10. Tức là bị bỏ sót nếu dòng số 10 ban đầu cũng thỏa mãn
 
Upvote 0
@Chủ bài đăng:
Bạn thử thực hành trên trang tính các công đoạn sau:
1./ (Dùng chuột) chọn 1 dòng có dữ liệu
2./ Tiến hành xóa (nguyên dòng)
3./ Xem thử dòng (dữ liệu) nào đã thay chỗ cho dòng bị xóa

Sau 3 công đoạn này bạn có kết luận gì không?
 
Upvote 0
Mình hay dùng Range("A1") như vậy trực quan nhìn trên bảng tính hơn.
Khi xóa dùng EntireRow.Delete sẽ mất dòng, dòng bên dưới sẽ đôn lên 1 dẫn đến chạy kết quả bị sai (***), nên quét từ dưới lên như BuiQuangThuan sẽ hợp lý hơn.

*** Giải thích thêm: giả sử khi i chạy đến 5, phát hiện đúng logic sau đó xóa dòng 5 thì dòng số 6 sẽ đôn lên biến thành 5, nhưng theo lệnh for i tiếp tục sẽ thành 6, dẫn ra cái dòng 6 đáng lẽ sẽ được kiểm tra, nhưng do bị đôn lên thành dòng 5, dẫn đến bị bỏ lọt.

Mã:
Sub Xoa()
    Dim Lr As Long, i As Long
    With Sheets("TH")
        Lr = .Range("E" & Rows.Count).End(xlUp).Row
        If Lr <= 9 Then Exit Sub
  
        For i = Lr To 9 Step -1
            If .Range("E" & i).Value = "Anh Thu" Or _
               .Range("E" & i).Value = "Anh Dung" Or _
               .Range("E" & i).Value = "Anh Hung" _
               Then .Range("E" & i).EntireRow.Delete
        Next i
    End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Em xin cảm ơn các anh/chị rất nhiều!
Bài đã được tự động gộp:

Tham khảo code đã sửa. (làm theo gọi ý của @BuiQuangThuan )
Mã:
Sub Xoa()
Dim Lr As Long, i As Long, Rng As Range
    Sheets("TH").Select
    Lr = ActiveSheet.Range("E" & Rows.Count).End(xlUp).Row
    If Lr <= 8 Then Exit Sub
    For i = 9 To Lr
        If Cells(i, 5) = "Anh Thu" Or Cells(i, 5) = "Anh Dung" Or Cells(i, 5) = "Anh Hung" Then
            If Rng Is Nothing Then
                Set Rng = Cells(i, 5)
            Else
                Set Rng = Union(Rng, Cells(i, 5))
            End If
        End If
    Next i
    ' Rng.Select
    Rng.EntireRow.Delete
End Sub
code chạy nhanh, nếu được thì bạn giải thích các dòng lệnh giúp
Mình đọc mà cũng còn nhiều điểm còn mơ hồ
Cảm ơn bạn nhé!
 
Lần chỉnh sửa cuối:
Upvote 0
. . . . code chạy nhanh,. . .
Đúng là Code sẽ nhanh hơn cách thường tình là xóa từng dòng;
Nhưng với số dòng hàng vạn thì còn cách khác nhanh hơn:

Khai báo 1 biến mảng để chứa dữ liệu (DL)
B1.0: Xác định số dòng chứa DL (có dòng cần xóa)
B1.1 Khai báo thêm 1 mảng để chứa các dòng DL không cần xóa (Như aKQ() )
B2: Cho vùng DL này vô mảng để duyệt
B3: Tạo vòng lặp duyệt mảng DL;
Trong quá trình duyệt, dòng nào không thỏa điệu kiện xóa thì tăng biến đếm lên 1 & tiến hành ghi vô mảng aKQ()
B4: Sau khi duyệt xong ta kiểm tra
B4.1 Nếu mảng aKQ() có DL:
→ Xóa toàn bộ vùng DL;
→ Ghi DL từ mảng aKQ() lên trang tính;
B4.2 Nếu aKQ() là Nothing thì gởi lời chào tạm biệt!

Chúc bạn thành công nha, chủ bài đăng!
 
Lần chỉnh sửa cuối:
Upvote 0
code chạy nhanh, nếu được thì bạn giải thích các dòng lệnh giúp
Vì bạn có ý chí học hỏi nên mình cũng chia sẻ như sau:
1- Khi loop qua vài ngàn dòng, tại mỗi dòng mình đều dùng lệnh xoá dòng, tức là 1 hành động tương tác với vùng ô trên sheet, sẽ dẫn đến tốc độ xử lý sẽ giảm nghiêm trọng
2- Do đó, có nhiều cách, trong đó phổ biến là dùng Union (như bạn HUONGHCKT đã làm).
Hãy hình dung Union là 1 nơi để tập hợp các cells thoả điều kiện và muốn xoá, khi loop qua cells và kiểm tra, nếu thoả thì chưa vội delete, mà lưu trữ nó vào Union.
Cuối cùng khi vòng lặp kết thúc thì mới lôi cái Union ra và ra lệnh xoá 1 lần duy nhất
3- Một cách khác mình hay dùng, là lập 1 biến array "data" để lưu giá trị, và khi duyệt qua thì duyệt qua biến này chứ không lần mò trên sheet sẽ tốn thời gian
VD: với rng lưu data gốc, và res lưu kết quả
Dim rng as Varian
rng = range("E5:E1000").value
Redim res(1 to ubound(rng), 1 to 1)
For i=1 to ubound(rng)
If .....gì đó... then
res(i,1)="#1/DIV"
End if
Next
Như vậy bạn đã có biến kết quả, bao gồm có các ký tự lỗi (Error), sau đó dán nó vào 1 cột nào đó chưa dùng đến, VD: ZZ
Sau đó dùng cái Specialcells(XLError) để xoá 1 lần các dòng có ký tự Error này

Bằng cách này thì không phải duyệt từng dòng trên sheet, sẽ làm tăng tốc đáng kể.
 
Upvote 0
Mã:
            If Rng Is Nothing Then
                Set Rng = Cells(i, 5)
            Else
                Set Rng = Union(Rng, Cells(i, 5))
            End If

- Union như dịch ra là "liên hợp", thay vì khi thỏa điều kiện thì bạn xóa ngay khi dùng for như bài #10, thì sẽ tập hợp nó lại. Sau cùng tập hợp hết thì xóa, bạn tưởng tượng đang click chuột và nhấn giữ Ctrl

- Vì đối số của Union là Range nên khi "lần đầu" chưa có range nào được gán thì dùng Set Rng = Union(Rng, Cells(i, 5)) được hiểu là hãy nối cái Rng cũ đã có với cái Cells(i,5) này giúp tôi. Lúc này sẽ lỗi, lúc này Rng Empty, do vậy cần phải bẫy cái Nothing.
 
Upvote 0
. . .
Hãy hình dung Union là 1 nơi để tập hợp các cells thoả điều kiện và muốn xoá, khi loop qua cells và kiểm tra, nếu thoả thì chưa vội delete, mà lưu trữ nó vào Union.
Cuối cùng khi vòng lặp kết thúc thì mới lôi cái Union ra và ra lệnh xoá 1 lần duy nhất
Ông Bi Bo này nói theo ngôn ngữ dân dã quá đi!
Union() là 1 phương thức dùng để liên kết thành 1 từ 2 hay nhiều vùng ô (thỏa điều kiện nào đó)
 
Upvote 0
Em cảm ơn các anh
Vì em còn nhiều code, do nó duyệt từng ô nên khá chậm
Do đó em muốn nghiên cứu, để cải tiến thêm các code của em
Nếu được các bài mẫu thì em dễ làm theo hơn
Đúng là Code sẽ nhanh hơn cách thường tình là xóa từng dòng;
Nhưng với số dòng hàng vạn thì còn cách khác nhanh hơn:

Khai báo 1 biến mảng để chứa dữ liệu (DL)
B1.0: Xác định số dòng chứa DL (có dòng cần xóa)
B1.1 Khai báo thêm 1 mảng để chứa các dòng DL không cần xóa (Như aKQ() )
B2: Cho vùng DL này vô mảng để duyệt
B3: Tạo vòng lặp duyệt mảng DL;
Trong quá trình duyệt, dòng nào không thỏa điệu kiện xóa thì tăng biến đếm lên 1 & tiến hành ghi vô mảng aKQ()
B4: Sau khi duyệt xong ta kiểm tra
B4.1 Nếu mảng aKQ() có DL:
→ Xóa toàn bộ vùng DL;
→ Ghi DL từ mảng aKQ() lên trang tính;
B4.2 Nếu aKQ() là Nothing thì gởi lời chào tạm biệt!

Chúc bạn thành công nha, chủ bài đăng!
Bài của bác, giảng từ căn bản, nhưng em thì học mò và bắc chước. Em sẽ cố
Mã:
            If Rng Is Nothing Then
                Set Rng = Cells(i, 5)
            Else
                Set Rng = Union(Rng, Cells(i, 5))
            End If

- Union như dịch ra là "liên hợp", thay vì khi thỏa điều kiện thì bạn xóa ngay khi dùng for như bài #10, thì sẽ tập hợp nó lại. Sau cùng tập hợp hết thì xóa, bạn tưởng tượng đang click chuột và nhấn giữ Ctrl

- Vì đối số của Union là Range nên khi "lần đầu" chưa có range nào được gán thì dùng Set Rng = Union(Rng, Cells(i, 5)) được hiểu là hãy nối cái Rng cũ đã có với cái Cells(i,5) này giúp tôi. Lúc này sẽ lỗi, lúc này Rng Empty, do vậy cần phải bẫy cái Nothing.
Giải thích như bạn mình thấy hiểu hơn 1 tý
À bi giờ mới phát hiện ra, nếu dữ liệu trong bài không có ô nào thoả điều kiện thì bị báo lỗi, vậy bài trên ta phải bẫy lỗi như thế nào?
Vì bạn có ý chí học hỏi nên mình cũng chia sẻ như sau:
1- Khi loop qua vài ngàn dòng, tại mỗi dòng mình đều dùng lệnh xoá dòng, tức là 1 hành động tương tác với vùng ô trên sheet, sẽ dẫn đến tốc độ xử lý sẽ giảm nghiêm trọng
2- Do đó, có nhiều cách, trong đó phổ biến là dùng Union (như bạn HUONGHCKT đã làm).
Hãy hình dung Union là 1 nơi để tập hợp các cells thoả điều kiện và muốn xoá, khi loop qua cells và kiểm tra, nếu thoả thì chưa vội delete, mà lưu trữ nó vào Union.
Cuối cùng khi vòng lặp kết thúc thì mới lôi cái Union ra và ra lệnh xoá 1 lần duy nhất
3- Một cách khác mình hay dùng, là lập 1 biến array "data" để lưu giá trị, và khi duyệt qua thì duyệt qua biến này chứ không lần mò trên sheet sẽ tốn thời gian
VD: với rng lưu data gốc, và res lưu kết quả
Dim rng as Varian
rng = range("E5:E1000").value
Redim res(1 to ubound(rng), 1 to 1)
For i=1 to ubound(rng)
If .....gì đó... then
res(i,1)="#1/DIV"
End if
Next
Như vậy bạn đã có biến kết quả, bao gồm có các ký tự lỗi (Error), sau đó dán nó vào 1 cột nào đó chưa dùng đến, VD: ZZ
Sau đó dùng cái Specialcells(XLError) để xoá 1 lần các dòng có ký tự Error này

Bằng cách này thì không phải duyệt từng dòng trên sheet, sẽ làm tăng tốc đáng kể.
Đọc bài của anh thấy nó quen quen, giống như Dic thì phải
 
Upvote 0
Đọc bài của anh thấy nó quen quen, giống như Dic thì phải
Dic nào ở đây, có cái nào đòi hỏi "duy nhất" đâu mà Dic.
Bài đã được tự động gộp:

Ông Bi Bo này nói theo ngôn ngữ dân dã quá đi!
Union() là 1 phương thức dùng để liên kết thành 1 từ 2 hay nhiều vùng ô (thỏa điều kiện nào đó)
Hic, bác Sa, chưa đủ dân dã đâu. Phải giải thích thế này:
Bạn có kế hoạch là ghé 1000 địa chỉ để nhận tiền, quà cứu trợ bão lũ.
Nếu bạn cứ ghé được 1 nơi, thu tiền xong, lại đi phát quà, sau đó quay lại nơi kế tiếp lặp lại như thế cho đến địa chỉ thứ 1000, vậy khi nào mới xong đây?
Tại sao không sắm cái túi to to (UNION), khi thu xong bỏ luôn vào đấy, xong việc làm 1 chuyến đi phát thôi?
 
Upvote 0
À bi giờ mới phát hiện ra, nếu dữ liệu trong bài không có ô nào thoả điều kiện thì bị báo lỗi, vậy bài trên ta phải bẫy lỗi như thế nào?
Hỏi lại bạn một tý, trường không có điều thỏa mãn tất cả thì Rng lúc này là gì ?
 
Upvote 0
Nếu không thỏa mãn điều kiện thì trừ việc khai báo biến Rng As Range
thì Rng chưa được gán hay đả động gì cả thì sao mà Rng.EntireRow.Delete được.
Lúc này Rng rỗng mà, thì phải kiểm tra Rng 1 lần nữa, nếu nó không rỗng thì mới tiến hành xóa dòng.
Mã:
If Not Rng Is Nothing Then Rng.EntireRow.Delete
 
Upvote 0
Web KT

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

Back
Top Bottom