Tìm giúp lỗi trong sử dụng SpeacialCells.

  • Thread starter Thread starter sealand
  • Ngày gửi Ngày gửi
Liên hệ QC

sealand

Thành viên gạo cội
Tham gia
16/5/08
Bài viết
4,883
Được thích
7,688
Giới tính
Nam
Nghề nghiệp
Kế Toán
Mình sử dụng phương thức lọc AutoFilter và sử dụng SpeacialCells để trích rút dữ liêu. Kết quả trả về không đúng với thực tế.
Nhờ các bạn kiểm tra giùm xem code đếm của Form lỗi ở đâu
Mô tả thì khó, các bạn xem trong Form giùm.
 

File đính kèm

Mình sử dụng phương thức lọc AutoFilter và sử dụng SpeacialCells để trích rút dữ liêu. Kết quả trả về không đúng với thực tế.
Nhờ các bạn kiểm tra giùm xem code đếm của Form lỗi ở đâu
Mô tả thì khó, các bạn xem trong Form giùm.
Anh dùng Vung.SpecialCells(xlCellTypeVisible).Rows.Count e rằng không ăn thua
Cách của em là resize thành 1 cột trước, sau đó đếm số cells
Kiểu vầy:
PHP:
Sub THOP()
  With TH.Range(TH.[A3], TH.[L65536].End(xlUp))
    Me.TextBox2 = WorksheetFunction.CountIf(.Resize(, 1).Offset(, 2), Me.ComboBox1)
    .AutoFilter 3, Trim(Me.ComboBox1)
    Me.TextBox1 = Intersect(.Resize(, 1), .Offset(1), .SpecialCells(12).EntireRow).Count
    .AutoFilter
  End With
End Sub
Anh có thể thí nghiệm thế này:
- Chọn đại 1 vài cell không liên tục nhau
- Chạy code này:
PHP:
Sub Test()
  MsgBox Selection.Rows.Count
End Sub
Sẽ thấy kết quả sai bét (chưa dùng đến SpecialCells thì nó cũng đã sai rồi)
 
Lần chỉnh sửa cuối:
Upvote 0
Em thấy file của Anh sealand rất lạ. Bình thuờng nếu sau khi autofilter, selection.count sẽ đúng (em đã test thử nhiều lần bằng cách cho tạm số liệu và auto filter sau đó thử
selection.count )
nhưng riêng sheet TH anh SeaLan thì selection.count ra kết quả lung tung (chỉ sheet TH thôi)
chẳng biết sao nữa
 
Upvote 0
Em đã chạy thử thấy code sau đúng Anh ạh
chỉ thêm đoạn sau
PHP:
 Set rg1 = Range("C4:C" & [C65000].End(xlUp).Row).SpecialCells(12)

Me.TextBox1 = rg1.Count
</span></span>
PHP:
Sub THOP()
Dim i, dg
Dim rg, rg1 As Range
i = TH.[a56536].End(xlUp).Row
On Error Resume Next
With TH
.Range("A3:L" & i).AutoFilter
dg = Application.WorksheetFunction.CountIf(TH.Range("C4:C" & i), Me.ComboBox1)
.Range("A3:L" & i).AutoFilter Field:=3, Criteria1:=Trim(Me.ComboBox1)
        Set rg = .AutoFilter
        Set rg1 = Range("C4:C" & [C65000].End(xlUp).Row).SpecialCells(12)

Me.TextBox1 = rg1.Count
Me.TextBox2 = dg
.Range("A3:L" & i).AutoFilter
rg.Select
End With
Set rg = Nothing
set rg1 = nothing
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Mình sử dụng phương thức lọc AutoFilter và sử dụng SpeacialCells để trích rút dữ liêu. Kết quả trả về không đúng với thực tế.
Nhờ các bạn kiểm tra giùm xem code đếm của Form lỗi ở đâu
Mô tả thì khó, các bạn xem trong Form giùm.

Đếm theo Cells thì chính xác hơn đến theo Rows tuy nhiên phải chia cho cột
PHP:
Me.TextBox1 = rg.Cells.Count / rg.Columns.Count
 
Upvote 0
Em e là cách của bác Trung Chinh chưa được?
 
Upvote 0
Ôi, thật thất lỗi! Hôm nay nhà có khách ở quê ra chơi giờ mới vào được và tất nhiên là chưa xem kỹ các bài của anh em được. Sealand xin được cám ơn tất cả anh em.
Đây là đoạn code gần như nguyên mẫu của Bác Sa_DQ ở bài này: . Trước nay mình sử dụng nó khá ổn cho các mục đích trích rút. Đây là trường hợp đầu tiên mình vướng thế này. Mình đã nghi rằng hay là mình có thói quen xấu là không xoá biến đối tượng khi không còn dùng nữa, ví dụ set Rg= Range(...) Khi không dùng nữa phải set Rg=Nothing để giải phóng bộ nhớ, tránh nhiễu loạn không kiểm soát hết. Nhưng kiểm tra thì chưa hẳn.
Có 2 điều kỳ lạ nữa đối với file này:
-Các bạn để ý 2 đoạn tô màu đỏ:
Set rg = .AutoFilter.Range.Offset(1, 0).Resize(.AutoFilter.Range.Rows. _
Count - 1
).SpecialCells(xlCellTypeVisible)
Me.TextBox1 = rg.Rows.Count
Giá trị trả về của 2 đoạn này phải bằng nhau chứ? Nhưng thực tế ở đây lại khác nhau và nó thay đổi mà mình để ý không ra quy luật
-Đây là dữ liệu mẫu cua Thanhnhanubnd . Khi kẹt ở đây mình xoay ra sử dụng Find trong bài này nhưng vẫn không ổn với 3 điều kiện cuối. Tức là phương thức Find cũng dính "chưởng" với file này.
Vậy rất mong được cùng các bạn tìm ra mấu chốt để giải quyết file này và làm kinh nghiệm cho các trường hợp tương tự.
Cám ơn.
 
Lần chỉnh sửa cuối:
Upvote 0
Có 2 điều kỳ lạ nữa đối với file này:
-Các bạn để ý 2 đoạn tô màu đỏ:
Set rg = .AutoFilter.Range.Offset(1, 0).Resize(.AutoFilter.Range.Rows. _
Count - 1
).SpecialCells(xlCellTypeVisible)
Me.TextBox1 = rg.Rows.Count
Giá trị trả về của 2 đoạn này phải bằng nhau chứ? Nhưng thực tế ở đây lại khác nhau và nó thay đổi mà mình để ý không ra quy luật
.
Anh Set Rg như vậy là.. sai quá trời luôn anh ơi!
- Thứ nhất: Rows Properties không làm việc được với multiple Selection (anh có thể xem trong Help)
Tương tự thế đối với Columns Properties ---> Vì thế cách của anh TrungChinh vẫn có thể tiềm ẩn sai sót
- Thứ hai: Không thể Resize multiple Selection ---> Ví dụ: Anh quét chọn A1:C4A7:C10 rồi chạy code này:
PHP:
Sub Test()
  Selection.Resize(2).Select
End Sub
Chắc chắn nó sẽ báo lỗi (có thể anh dùng On Error Resume Next ở đầu code nên nó.. cho qua luôn)
Mấu chốt là ở 2 điểm vừa nêu trên thôi
Nói thêm:
Để xác định vùng dữ liệu nằm dưới dòng tiêu đề, em dùng cách này:
PHP:
Sub Test()
  Dim Rg As Range
  With Selection
    Set Rg = Intersect(.Cells, .Offset(1))
    Rg.Select
  End With
End Sub
Và để xác định vùng dữ liệu Visible nằm dưới dòng tiêu đề sau khi AutoFilter:
PHP:
Sub Test()
  Dim Rg As Range
  With ActiveSheet.AutoFilter.Range
    Set Rg = Intersect(.Cells, .Offset(1)).SpecialCells(12)
    Rg.Select
  End With
End Sub
Dùng Intersect anh à! ---> Chắc ăn như bắp
 
Lần chỉnh sửa cuối:
Upvote 0
Cám ơn Anh NDU
nhân tiện cho em hỏi có thực sự cần thiết set trả Rg = nothing không ah?
 
Upvote 0
Cám ơn Anh NDU
nhân tiện cho em hỏi có thực sự cần thiết set trả Rg = nothing không ah?
Cần hay không còn tùy trường hợp...
- Bạn khai báo 1 biến Object nằm trên đầu code theo kiểu vầy:
PHP:
Dim Rg As Range
Sub Test()
  .......
End Sub
Trường hợp này sẽ cần động tác Set Rg = Nothing (nếu không, biến ấy vẫn tồn tại trong vùng nhớ)
- Bạn khai báo biến nằm trong 1 sub thì không cần động tác trên
Nói chung là có thể THỪA nhưng đừng nên THIẾU
Bạn có thể tham khảo bài này: Giải phóng bộ nhớ cho biến
 
Upvote 0
Mình thắc mắc nó là chỗ này :

Dim tam
Sheet1.Rows(1&":" & i).ClearContents
...............
rg.Copy Sheet1.[a1]
tam=rg
Me.ListBox1.List()=tam
Me.TextBox1 = rg.Rows.Count


.................
Trong đoạn code trên thì đoạn màu xanh chắc ăn. Nhưng đoạn màu tím thì vỡ, tức là không phải dùng Rows sai. Cùng 1 range nếu chép sang vùng khác thì chuẩn. Nhưng gán cho biến Variant nạp vào ListBox hay đếm dòng thì lại sai. Trước đây, mình thường dùng Filter rồi gán biến Variant để nạp ListBox, ComboBox chưa hề gặp thế này.

Còn mình sẽ sử dụng phương pháp dùng Intersect như Ndu giới thiệu. Đây theo mình cũng là 1 tuyệt chiêu đây. Trong khi tạo Report thì kỹ thuật này khá hiệu quả.
 
Lần chỉnh sửa cuối:
Upvote 0
Ndu à, dùng Intersect kết quả y hệt đoạn code của bác Sa_DQ nhưng nó gọn hơn thôi.
 
Upvote 0
Ndu à, dùng Intersect kết quả y hệt đoạn code của bác Sa_DQ nhưng nó gọn hơn thôi.
Cái topic anh giới thiệu về SpecialCells của bác SA_DQ em vừa xem qua
trong code của bác SA_DQ có đoạn:
PHP:
MsgBox ActiveSheet.UsedRange.SpecialCells(xlCellTypeVisible).Rows.Count, , Rng.Address
Em nghĩ rằng bác có nhầm lẫn gì đây ---> Code trên không thể nào chính xác được
Anh cứ thí nghiệm thế này:
- Mở 1 Wb mới
- Gõ đại gì đó vào vùng C3:G12
- Cho ẩn dòng 5 và dòng 9
- Chạy code này:
PHP:
Sub Test()
 With ActiveSheet.UsedRange
   .SpecialCells(xlCellTypeVisible).Select
   MsgBox .SpecialCells(xlCellTypeVisible).Rows.Count
 End With
End Sub
Anh sẽ thấy kết quả = 2 mà đúng ra nó phải = 8
Đơn giản vì Rows Properties chỉ tính cho Areas đầu tiên mà thôi, mấy vùng thuộc các Areas tiếp theo nó bỏ qua luôn
Thí nghiệm trên nếu muốn cho kết quả đúng thì phải vầy:
PHP:
Sub Test()
 With ActiveSheet.UsedRange
   .SpecialCells(xlCellTypeVisible).Select
    With Intersect(.Resize(, 1), .SpecialCells(xlCellTypeVisible))
      MsgBox .Cells.Count
    End With
 End With
End Sub
Có lẽ bác SA_DQ phải chỉnh lại bài viết của mình rồi
 
Lần chỉnh sửa cuối:
Upvote 0
Mình lờ mờ hiểu vấn đề này 1 chút từ chính phát hiện của Ndu nhưng Ndu không kiểm tra tiếp
-Thực chất cái Rg trả về theo code của bác Sa_DQ là tổ hợp của rất nhiều "mảnh" ghép lại sau khi loại trừ các vùng không thoả mãn điều kiện lọc. Mình đã thử bằng lệnh:

MsgBox Rg.Areas.count.

Lệnh Rg.rows.count thưc ra nó chính là Rg.Areas(1).rows.count

Khi dùng lệnh Copy là nó cũng minh bạch chép lần lượt từng mảnh liên tiếp nên vùng đích. Vô hình dung việc dán liên tiếp này cho ta 1 vùng mới là kết quả trọn vẹn. Và đây là trường hợp đặc biệt mà thôi.
Mình thử bằng Code sau thấy chuẩn hoàn toàn:
...............................
dim n, i as Integer
for i=1 to Rg.Areas.Count
n=n+RgAreas(i).Rows.count
Next
Msgbox "So dong cua vung loc :" & n
................................


Mặt khác, khi ta gán vùng này cho 1 biến Variant thì đây tương ứng như 1 mảng đa chiều và cần có cú pháp hợp lý để chủ động lấy dữ liệu.

Tóm lại,
- Diều hay nhất là chuyển được Rg từ dang Multi_Range thành dạng Unique_Range, thuận lợi cho việc sử lý về sau.\
- Nếu chưa chuyển được thì phải soát xét hết các vùng của biến.
 
Upvote 0
Web KT

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

Back
Top Bottom