Xử lý code: Tìm giá trị trùng 2 cột và tính kết quả

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

boyxin

Members actively
Tham gia
10/3/08
Bài viết
1,664
Được thích
2,335
Chào các bác. Em gặp vấn đề

Lấy từng mã hàng (cột G) Tìm bên cột C
Nếu thấy thì điền Gtrị bán vào dòng tương ứng ở cột E và lấy Gtrị ở cột D - Gtrị ở cột E = Gtrị ở cột F (Tồn 2)
Chi tiết trong File đính kèm


Mới tập tẹ VBA: Em dùng Find nhưng khi cột C khoảng 5000 dòng và cột G có khoảng 500 dòng thì thấy lâu quá

Mong các bác giúp giải pháp xử lý nhanh hơn
 

File đính kèm

Lần chỉnh sửa cuối:
Chào các bác. Em gặp vấn đề

Lấy từng mã hàng (cột G) Tìm bên cột C
Nếu thấy thì điền Gtrị bán vào dòng tương ứng ở cột E và lấy Gtrị ở cột D - Gtrị ở cột E = Gtrị ở cột F (Tồn 2)
Chi tiết trong File đính kèm


Mới tập tẹ VBA: Em dùng Find nhưng khi cột C khoảng 5000 dòng và cột G có khoảng 500 dòng thì thấy lâu quá

Mong các bác giúp giải pháp xử lý nhanh hơn

Nếu anh thêm cái này thì sẽ nhanh hơn rất nhiều khi dữ liệu lớn

Application.EnableEvents = False
Application.ScreenUpdating = False

Em chưa thử nhưng em nghĩ là nếu ta dùng Find để tìm ra vùng chứa dữ liệu bên sheet ton và bán, sau đó copy và dán thì sẽ nhanh hơn là Advancedfilter
 
Upvote 0
Bạn thử so kiểm lại xem sao?!

PHP:
Option Explicit
Sub BoyXin()
 Dim allRng As Range, sRng As Range
 Dim lRs As Long, Jj As Long
 Dim Timer_ As Double
 
 lRs = [b65500].End(xlUp).Row:          Application.ScreenUpdating = False
 [e2].Resize(lRs, 2).Clear:             Timer_ = Timer
 Set allRng = Range([c2], Cells(lRs, "C"))
 lRs = [g65500].End(xlUp).Row
 For Jj = 3 To lRs
    With Cells(Jj, "G")
        Set sRng = allRng.Find(what:=.Value, LookIn:=xlFormulas, lookAt:=xlWhole)
        If Not sRng Is Nothing Then
            sRng.Offset(, 2) = .Offset(, 1)
            sRng.Offset(, 3) = sRng.Offset(, 1) - .Offset(, 1)
        End If
    End With
 Next Jj
 MsgBox Timer - Timer_, , "Total:"
End Sub
 
Upvote 0
cảm ơn ChanhTQ@: Có nhanh hơn chút nhưng với dữ liệu lớn thì vẫn chậm vì dù sao cũng vẫn cứ phải lấy từng phần từ ở cột này so với các phần tử ở cột kia ...
Liệu có cách nào khác không?
giống như tìm phần giao nhau giữa hai miền giá trị

 
Upvote 0
Nếu được phép sắp xếp hai cột dữ liệu lại, thì

Sẽ nhanh hơn trong việc tìm kiếm: Vì lúc đó ta thu nhỏ được vùng tìm kiếm trong quá trình tìm kiếm record kế tiếp!

Thân ái.
 
Upvote 0
Sẽ nhanh hơn trong việc tìm kiếm: Vì lúc đó ta thu nhỏ được vùng tìm kiếm trong quá trình tìm kiếm record kế tiếp!

Thân ái.

các cột này do AdF mà có, dùng để xử lý. không phải là dữ liệu gốc nên sort thế nào cũng được

Chỉ cần: Tổng thời gian (từ lúc AdF - Sort - Tìm kiếm và tính toán ...) càng ít càng tốt

Cho hỏi thêm: For Jj = 3 To lRs so với For Each ... in ... thì cái nào nhanh hơn
 
Lần chỉnh sửa cuối:
Upvote 0
For Jj = 3 To lRs so với For Each ... in ... thì cái nào nhanh hơn
Nếu Range... không hide dòng thì giống nhau, cái nào cũng duyệt cả.
Còn bài của BoyXin hỏi sao giống Vlookup quá, dùng Vlookup nhanh hơn nhiều. Cùng lắm dùng VBA cho Vlookup.
 
Upvote 0
các cột này do AdF mà có, dùng để xử lý. không phải là dữ liệu gốc nên sort thế nào cũng được
Chỉ cần: Tổng thời gian (từ lúc AdF - Sort - Tìm kiếm và tính toán ...) càng ít càng tốt
Giảm thời gian thêm xíu đây (Gần như 1/2):
PHP:
Option Explicit
Sub BoyXin()
 Dim allRng As Range, sRng As Range, aRng As Range
 Dim lRs As Long, Jj As Long
 Dim Timer_ As Double
 
 lRs = [b65500].End(xlUp).Row:          Application.ScreenUpdating = False
 Timer_ = Timer:                        [e2].Resize(lRs, 2).Clear
 Columns("B:D").Sort Key1:=[b2], Order1:=xlAscending, Header:=xlGuess, OrderCustom:=1
 Columns("G:H").Sort Key1:=[G2], Order1:=xlAscending, Header:=xlGuess, OrderCustom:=1
 Set allRng = Range([c1], Cells(lRs, "C"))
 lRs = [g65500].End(xlUp).Row
 For Jj = 2 To lRs
    With Cells(Jj, "G")
        Set aRng = sRng
        If sRng Is Nothing Then Set aRng = allRng.Cells(1, 1)
        Set sRng = allRng.Find(what:=.Value, LookIn:=xlFormulas, _
            lookAt:=xlWhole, After:=aRng)
        If Not sRng Is Nothing Then
            sRng.Offset(, 2) = .Offset(, 1)
            sRng.Offset(, 3) = sRng.Offset(, 1) - .Offset(, 1)
        End If
    End With
 Next Jj
 MsgBox Timer - Timer_, , "Total:"
End Sub
Cho hỏi thêm: For Jj = 3 To lRs so với For Each ... in ... thì cái nào nhanh hơn
Bạn thử được mà?!
 
Upvote 0
Nếu Range... không hide dòng thì giống nhau, cái nào cũng duyệt cả.
Còn bài của BoyXin hỏi sao giống Vlookup quá, dùng Vlookup nhanh hơn nhiều. Cùng lắm dùng VBA cho Vlookup.
Giải bằng Vlookup:
Mã:
Sub VlookupMaHang()
On Error Resume Next
Dim rgMh As Range
Dim GtTon As Double, rC As Long, rG As Long, r As Long
Sheets("Main").Select
rC = Cells(1, 3).End(xlDown).Row
rG = Cells(1, 7).End(xlDown).Row
Range(Cells(3, 5), Cells(rG, 6)).ClearContents
Set rgMh = Range(Cells(3, 3), Cells(rC, 4))
For r = 3 To rG
  GtTon = Application.WorksheetFunction.VLookup(Cells(r, 7), rgMh, 2, 0)
  If Err.Number = 0 Then
    Cells(r, 5) = Cells(r, 8)
    Cells(r, 6) = Cells(r, 8) - GtTon
  Else
    Err.Number = 0
  End If
  'if gtton>0 then
Next
End Sub
Thấy chạy nhanh. Boyxin thử lại xem có đúng không.
 

File đính kèm

Upvote 0
boyxin chân thành cảm ơn

Hi, cách nào cũng hay

Đây là thành quả
Chưa kịp test cách dùng VLOOKUP (thấy KQ kín đặc cả, chắc phải chỉnh ở đâu đó mới ổn)
Code của Thầy Long phải sửa lại, do để ngược tham chiếu.
PHP:
Sub VlookupMaHang()
On Error Resume Next
Dim rgMh As Range
Dim GtTon As Double, rC As Long, rG As Long, r As Long
Application.ScreenUpdating = False
Sheets("Main").Select
rC = Cells(1, 3).End(xlDown).Row
rG = Cells(1, 7).End(xlDown).Row
Range(Cells(3, 5), Cells(rG, 6)).ClearContents
Set rgMh = Range(Cells(3, 7), Cells(rG, 8))
For r = 2 To rC
  GtTon = Application.WorksheetFunction.VLookup(Cells(r, 3), rgMh, 2, 0)
  If Err.Number = 0 Then
    Cells(r, 5) = GtTon
    Cells(r, 6) = Cells(r, 8) - GtTon
  Else
    Err.Number = 0
  End If
  'if gtton>0 then
Next
End Sub
Mà sao thấy nó chạy cũng chậm nhỉ. Hình như Vlookup, match cũng tựa như là find mà Find tối ưu hơn trong việc tìm thay vì For i.
Để minh làm thử cách này thử.
 
Upvote 0
Dùng mảng thấy có cải tiến một ít về tốc độ, gửi bạn xem thử nhé:

PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Rng As Range, allRng As Range, sRng As Range, aRng As Range
Dim lRs As Long, Jj As Long, Ii As Long, Timer_ As Double
Dim ro As Long
Dim a1(), a2(), a0()
Dim r0 As Range, r1 As Range, r2 As Range, r3 As Range
'----------------------------------------------------------------------------
If Target.Address = "$A$2" Then
    Timer_ = Timer
    Application.DisplayAlerts = False
    Application.ScreenUpdating = False
'----------------------------------------------------------------------------
    Set Rng = Sheets("ton").[a1].CurrentRegion
        Rng.AdvancedFilter 2, [A1:A2], [B2:D2]
    Set Rng = Sheets("ban").[a1].CurrentRegion
        Rng.AdvancedFilter 2, [A1:A2], [G2:H2]
    '[B3:D65535].SpecialCells(2, 23).Sort Key1:=[C3], Order1:=1, DataOption1:=1
    '[G3:H65535].SpecialCells(2, 23).Sort Key1:=[G3], Order1:=1, DataOption1:=1
    On Error Resume Next
    [E3:F65535].SpecialCells(2, 23).ClearContents
'----------------------------------------------------------------------------
    lRs = [b65500].End(xlUp).Row
    ro = [G65000].End(xlUp).Row
    Set ra = Range([C1], Cells(lRs, "C"))  ' cot chua ma hang
    Set r0 = Range([D1], Cells(lRs, "D"))  ' cot chua ton1
    Set r1 = Range([E1], Cells(lRs, "E"))  ' cot chua gia ban
    Set r2 = Range([F1], Cells(lRs, "F"))  ' cot chua ton2
    Set r3 = Range([G1], Cells(ro, "H"))  ' cot chua gia ban
 
    ReDim a1(lRs): ReDim a2(lRs): ReDim a0(lRs)
    a1 = r1: a2 = r2: a0 = r0
    For Ii = 3 To ro
        k = WorksheetFunction.Match(r3.Cells(Ii, 1), ra, 0)
        If k > 0 Then
            t = r3.Cells(Ii, 2)
            a1(k, 1) = t
            a2(k, 1) = a0(k, 1) - t
        End If
    Next
    r1 = a1: r2 = a2
'----------------------------------------------------------------------------
    Names("Extract").Delete
    Names("Criteria").Delete
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
    [J1] = Format(Timer - Timer_, "0#.###")
End If
End Sub

-hvl-
 
Upvote 0
Code của Thầy Long phải sửa lại, do để ngược tham chiếu.
Mà sao thấy nó chạy cũng chậm nhỉ. Hình như Vlookup, match cũng tựa như là find mà Find tối ưu hơn trong việc tìm thay vì For i.
Để minh làm thử cách này thử.
Cách mình viết sai yêu cầu. Thử cách mới không dùng For Next mà thay bằng ghi thẳng công thức vào bảng tính > Copy > Paste Special để hủy công thức.
Mã:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rC As Long, rG As Long, MyTime As Double
Dim RngGH As String
If Target.Address = "$A$2" Then
  Application.DisplayAlerts = False
  Application.ScreenUpdating = False
  MyTimer = Timer
  rC = Cells(1, 3).End(xlDown).Row
  rG = Cells(1, 7).End(xlDown).Row
  Range(Cells(3, 5), Cells(rC, 6)).ClearContents
  RngGH = Range(Cells(3, 7), Cells(rG, 8)).Address(, , xlR1C1)
  Range(Cells(3, 5), Cells(rC, 5)).Select
  Selection.FormulaR1C1 = "=VLOOKUP(" & "C3," & RngGH & ",2,0)"
  Range(Cells(3, 6), Cells(rC, 6)).Select
  Selection.FormulaR1C1 = "=RC[-2]-RC[-1]"
  Cells(3, 4).SpecialCells(xlCellTypeFormulas, 16).Select
  Selection.ClearContents
  Range(Cells(3, 5), Cells(rC, 6)).Select
  Selection.Copy
  Selection.PasteSpecial Paste:=xlPasteValues
  Application.CutCopyMode = False
  [J1] = Timer - MyTimer
End If
End Sub
Làm theo bài của ThuNghi, con trỏ phải ở A2 mới chạy.
 

File đính kèm

Upvote 0
Em nghĩ bài này dùng sumif, cứ tính cho xa.
Bổ sung:
Cột C: Duy nhất
Cột G: Duy nhất
Tìm giá trị cột H nếu Ci=Gj
=> Dùng sumif
Có thể dùng cách 2 như sau:
- Cột G&H nằm ở Sh khác.
- AdFi B:D: theo G
- for each - Sumif theo Cells invisible.
- Show all.
 
Upvote 0
Em nghĩ bài này dùng sumif, cứ tính cho xa.

SUMIF thế nào vậy bác, nhất thời em chưa nghĩ ra
--------------------------------------------------------

Sau khi được các bác giúp đỡ nhiệt tình, cách nào cũng hay, cũng mạnh nhưng mỗi cách sẽ được dùng vào 1 công việc cụ thể, thích hợp thì sẽ phát huy được sức mạnh tói đa của nó

Em vận dụng được chút ít trong bài giúp đỡ bạn thu_love. đã cải thiện tốc độ rất nhiều so với giải pháp lúc đầu của em

Nhưng vẫn còn vấn đề chưa được ưng ý, cụ thể là phần nhập và xử lý Data cho sheet INPUT
Có 2 file ton.xlsban.xls cần có được báo cáo nhanh như Sheet Main, em chuẩn bị trước sheet INPUT như trong file đính kèm
Mong các bác tiếp tục giúp đỡ, tư vấn để tốc độ xử lý nhanh hơn
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Em muốn khi tìm với giá trị ở cột D7 thì sẽ lấy thêm một giá trị nữa là giá nhập thì phải sửa công thức như thế nào vậy các anh


Cảm ơn các anh nhìu

Sửa lại code như sau

Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, [D7]) Is Nothing Then
Application.ScreenUpdating = False
Set Rng = Sheet1.[B1].CurrentRegion
Rng.AdvancedFilter 2, [E4:E5], [E7:G7]
Application.ScreenUpdating = True
End If
End Sub
 
Upvote 0
anh nào giúp em với
nếu ta không chọn một ngành hàng nào thì nó sẽ hiện ra tổng tổng và tổng doanh so bán
 

File đính kèm

Upvote 0
giúp em với
nếu ta không chọn một ngành hàng nào thì nó sẽ hiện ra tổng tổng và tổng doanh so bán

Từ File ReportBC.xls trong ReportBC.rar Sau khi INPUT dữ liệu vào:

  1. Tổng TỒN = ô D1 sheet INPUT
  2. Tổng BÁN = ô E1 sheet INPUT
  3. Tổng TỒN - BÁN = ô F1 sheet INPUT
Không thấy sao mà cứ thích tự làm khó mình vậy
------------------------------------------------------------------

Xem cách này được không?
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
cho em hỏi thêm một chút nhé
trong files bán nếu giá trị bán không phải ở cột E nữa
trong files ton nếu mã hàng, số lượng tồn và giá trị tông không khải ở cột B, E, F nữa
thì phải sửa code thế nào a?
 
Upvote 0
Web KT

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

Back
Top Bottom