Tìm Subtotal bằng VBA

Liên hệ QC

moihocvba

Thành viên thường trực
Tham gia
16/8/20
Bài viết
207
Được thích
49
Chào anh chị GPE!
Em có một bảng dữ liệu như này:

1612406380686.png

Em muốn tính tổng các cột từ Sum1 đến Sum5 theo cột Mã số, kết quả như thế này:
1612406545576.png


Nếu dữ liệu ít có thể dùng lệnh Subtotal của Excel cũng ra, nhưng vì file của em dữ liệu quá lớn (hơn 95.000 dòng), nên khi em dùng lệnh subtotal có sẵn của excel thì Excel của em đứng luôn. Nên em có ý tưởng đưa dữ liệu này vào mảng để xử lý sau đó dáng kết quả ra một nơi khác cho nhẹ ạ. Em up file lên đây nhờ các anh chị giúp em code để em học hỏi ạ!
Em cảm ơn anh chị nhiều!
 

File đính kèm

  • Subtotal.xlsb
    1.7 MB · Đọc: 67
Lần chỉnh sửa cuối:
OT loay hoay mãi một cột mà chưa được, nhờ Bạn @befaint góp ý ạ:
Mã:
Sub SumKhongSort()

    Dim Dic As Object, sMa As String, aChuaSum() As Variant, aSumSum() As Variant
    Dim r As Long, k As Long, eA As Long, c As Long, i As Double, a As Long
  
    With Sheet1
        aChuaSum = .Range(sR).CurrentRegion.Value2
        eA = UBound(aChuaSum, 1): a = UBound(aChuaSum, 2) + 1
        If eA < 2 Then Exit Sub
        ReDim Preserve aChuaSum(1 To eA, 1 To a)
        ReDim aSumSum(1 To eA * 2, 1 To a)
        Set Dic = CreateObject("scripting.dictionary")
        For r = eA To 2 Step -1
            sMa = aChuaSum(r, 1)
            aSumSum(r, 1) = sMa
'            For c = 2 To a - 1
                'aSumSum(r, 2) = aChuaSum(r, 2)
                If Not Dic.Exists(sMa) Then
                    k = r + 1
                    Dic.Add sMa, k
                    aSumSum(k, 2) = aChuaSum(r, 2)
                Else
                    i = Dic(sMa)
                    aSumSum(i, 1) = Empty
                    aSumSum(i, 2) = aSumSum(i, 2) + aChuaSum(r, 2)
                End If
'            Next c
        Next r
        .Range(sR).Offset(, 8).Resize(eA + k, a) = aSumSum
    End With
End Sub
Bạn đặt tên biến ngồ ngộ
Mã:
Sub SumKhongSort()
    Dim Dic As Object, sMa As String, aChuaSum() As Variant, aSumSum() As Variant
    Dim iKey, S, ik&, iSub&, sRow&
    Dim r As Long, k As Long, eA As Long, c As Long, i As Double, a As Long
   
    With Sheet1
        aChuaSum = .Range("A1").CurrentRegion.Value
        eA = UBound(aChuaSum, 1): a = UBound(aChuaSum, 2)
        If eA < 2 Then Exit Sub
        Set Dic = CreateObject("scripting.dictionary")
        For r = 2 To eA
            sMa = aChuaSum(r, 1)
            If Dic.exists(sMa) = False Then k = k + 1
            Dic.Item(sMa) = Dic.Item(sMa) & "," & r
        Next r
        sRow = eA + k - 1
        ReDim aSumSum(1 To sRow, 1 To a)
        k = 0
        For Each iKey In Dic.keys
          S = Split(Dic.Item(iKey), ",")
          iSub = k + UBound(S) + 1
          aSumSum(iSub, 1) = "Tong cong"
          For r = 1 To UBound(S)
            k = k + 1
            ik = CLng(S(r))
            aSumSum(k, 1) = aChuaSum(ik, 1)
            aSumSum(k, 2) = aChuaSum(ik, 2)
            aSumSum(iSub, 2) = aSumSum(iSub, 2) + aChuaSum(ik, 2)
          Next r
          k = k + 1
        Next iKey
        .Range("A2").Offset(, 8).Resize(sRow, a) = aSumSum
    End With
    With Sheet2
        '.Range("A2").Resize(sRow, a) = aSumSum
    End With
End Sub
 
Upvote 0
Bạn đặt tên biến ngồ ngộ
Mã:
Sub SumKhongSort()
    Dim Dic As Object, sMa As String, aChuaSum() As Variant, aSumSum() As Variant
    Dim iKey, S, ik&, iSub&, sRow&
    Dim r As Long, k As Long, eA As Long, c As Long, i As Double, a As Long
  
    With Sheet1
        aChuaSum = .Range("A1").CurrentRegion.Value
        eA = UBound(aChuaSum, 1): a = UBound(aChuaSum, 2)
        If eA < 2 Then Exit Sub
        Set Dic = CreateObject("scripting.dictionary")
        For r = 2 To eA
            sMa = aChuaSum(r, 1)
            If Dic.exists(sMa) = False Then k = k + 1
            Dic.Item(sMa) = Dic.Item(sMa) & "," & r
        Next r
        sRow = eA + k - 1
        ReDim aSumSum(1 To sRow, 1 To a)
        k = 0
        For Each iKey In Dic.keys
          S = Split(Dic.Item(iKey), ",")
          iSub = k + UBound(S) + 1
          aSumSum(iSub, 1) = "Tong cong"
          For r = 1 To UBound(S)
            k = k + 1
            ik = CLng(S(r))
            aSumSum(k, 1) = aChuaSum(ik, 1)
            aSumSum(k, 2) = aChuaSum(ik, 2)
            aSumSum(iSub, 2) = aSumSum(iSub, 2) + aChuaSum(ik, 2)
          Next r
          k = k + 1
        Next iKey
        .Range("A2").Offset(, 8).Resize(sRow, a) = aSumSum
    End With
    With Sheet2
        '.Range("A2").Resize(sRow, a) = aSumSum
    End With
End Sub
Con cảm ơn Bác @HieuCD đã chỉ dẫn ạ, con biết thêm được cách dùng 'For Each iKey In Dic.keys'
 
Upvote 0
Chào anh chị GPE!
Em có một bảng dữ liệu như này:

View attachment 253932

Em muốn tính tổng các cột từ Sum1 đến Sum5 theo cột Mã số, kết quả như thế này:
View attachment 253933


Nếu dữ liệu ít có thể dùng lệnh Subtotal của Excel cũng ra, nhưng vì file của em dữ liệu quá lớn (hơn 95.000 dòng), nên khi em dùng lệnh subtotal có sẵn của excel thì Excel của em đứng luôn. Nên em có ý tưởng đưa dữ liệu này vào mảng để xử lý sau đó dáng kết quả ra một nơi khác cho nhẹ ạ. Em up file lên đây nhờ các anh chị giúp em code để em học hỏi ạ!
Em cảm ơn anh chị nhiều!
Nếu Bạn muốn sử dụng thêm với phương pháp code bài 21 của Bác @HieuCD thì Bạn thay đoạn:
Mã:
            aSumSum(k, 2) = aChuaSum(ik, 2)
            aSumSum(iSub, 2) = aSumSum(iSub, 2) + aChuaSum(ik, 2)

Thành:
Mã:
                For c = 2 To a
                    aSumSum(k, c) = aChuaSum(ik, c)
                    aSumSum(iSub, c) = aSumSum(iSub, c) + aChuaSum(ik, c)
                Next c

Để có được tất cả các cột sum nhé, vì code Bác @HieuCD chỉ dẫn cho OT cách làm trong bài 19 chỉ ra cột Sum1 thôi ạ.
 
Upvote 0
Không phải vậy anh.
Kết quả thì vẫn gom lại một cụm, dòng tổng để dưới cụm đúng như yêu cầu.
Không sort ở đây là: Không sử dụng cách sort để gom các mã lại một chỗ và để tính tổng của cụm
Sort là căn bản của lập trình sử lý phát sinh (transaction processing). Thủ tục (có từ thời IBM còn ngự trị máy tính):
- sort
- bốc cái đầu tiên
- vòng lặp while not eof
- - nếu không giống cái trước thì
- - - kết thúc nhóm cũ
- - - chuẩn bị nhóm mới
- - (các code khác)
- - bốc cái kế
- end vòng lặp

Không sort là di ngược lại căn bản.
 
Upvote 0
OT thêm câu lệnh tô đậm các dòng Sum nhưng không biết đến khi nào code mới chạy xong, nhờ các Bác & các Bạn chỉ dẫn ạ:
Mã:
Public Function TangTocCode(TangToc As Boolean)
    Application.ScreenUpdating = Not (TangToc)
    Application.EnableEvents = Not (TangToc)
    Application.Calculation = IIf(TangToc, xlCalculationManual, xlCalculationAutomatic)
End Function

Sub SumKhongSort()
   
    On Error GoTo End_
   
    Call TangTocCode(True)
   
    Dim Dic As Object, sMa As String, aChuaSum() As Variant, aSumSum() As Variant
    Dim iKey, S, ik&, iSub&, sRow&, r As Long, k As Long, eA As Long, c As Long, a As Long
    Dim rng As Range, RngU As Range, rTam As Range
   
    Const ofset As Integer = 8
    Set rng = Sheet1.Range("A1")
    rng.CurrentRegion.Sort Key1:=rng, Order1:=xlAscending, Header:=xlYes
    aChuaSum = rng.CurrentRegion.Value
    eA = UBound(aChuaSum, 1): a = UBound(aChuaSum, 2)
    If eA < 2 Then Exit Sub
    Set Dic = CreateObject("scripting.dictionary")
    For r = 2 To eA
        sMa = aChuaSum(r, 1)
        If Not Dic.Exists(sMa) Then k = k + 1
        Dic.Item(sMa) = Dic.Item(sMa) & "," & r
    Next r
    sRow = eA + k - 1: k = 0
    ReDim aSumSum(1 To sRow, 1 To a)
    For Each iKey In Dic.Keys
        S = Split(Dic.Item(iKey), ",")
        iSub = k + UBound(S) + 1
        aSumSum(iSub, 1) = "Tong cong: "
        Set rTam = rng.Offset(iSub, ofset).Resize(, a)
        For r = 1 To UBound(S)
            k = k + 1
            ik = CLng(S(r))
            aSumSum(k, 1) = aChuaSum(ik, 1)
            For c = 2 To a
                aSumSum(k, c) = aChuaSum(ik, c)
                aSumSum(iSub, c) = aSumSum(iSub, c) + aChuaSum(ik, c)
            Next c
        Next r
        If RngU Is Nothing Then
            Set RngU = rTam
        Else
            Set RngU = Union(RngU, rTam)
        End If
        k = k + 1
    Next iKey
    With rng.Offset(1, ofset)
        .Clear
        .Resize(sRow, a) = aSumSum
    End With
    RngU.Font.Bold = True

     'Sheet2.Range("A2").Resize(sRow, a) = aSumSum
   
End_:

    Call TangTocCode(False)
    If Err.Number <> 0 Then MsgBox Err.Description, vbCritical, Err.Number
   
End Sub

Nếu chạy SumTruyenThong thì OK ạ:
Mã:
Sub SumTruyenThong()
    
    Dim Dic As Object, sMa As String, aChuaSum() As Variant, aSumSum() As Variant
    Dim r As Long, k As Long, eA As Long, c As Long, i As Double, a As Long
    Const sR As String = "A1"
    
    With Sheet1
        aChuaSum = .Range(sR).CurrentRegion.Value2
        eA = UBound(aChuaSum, 1): a = UBound(aChuaSum, 2) + 1
        If eA < 2 Then Exit Sub
        ReDim Preserve aChuaSum(1 To eA, 1 To a + 1)
        ReDim aSumSum(1 To eA, 1 To a)
        Set Dic = CreateObject("scripting.dictionary")
        For r = 2 To eA
            sMa = aChuaSum(r, 1)
            aChuaSum(r, a) = sMa
            For c = 2 To a - 1
                If Not Dic.Exists(sMa) Then
                    k = k + 1
                    Dic.Add sMa, k
                    aSumSum(k, a) = sMa & "Sub"
                    aSumSum(k, c) = aChuaSum(r, c)
                Else
                    i = Dic(sMa)
                    aSumSum(i, c) = aSumSum(i, c) + aChuaSum(r, c)
                End If
            Next c
        Next r
    End With
    
    With Sheet2.Range(sR)
        .Offset(, a - 1).Resize(eA + k).NumberFormat = "@"
        .Resize(eA, a).Value = aChuaSum
        .Offset(eA).Resize(k, a).Value2 = aSumSum
        .Offset(eA).Resize(k, a).Font.Bold = True
        .Resize(eA + k, a).Sort Key1:=.Offset(, a - 1), Order1:=xlAscending, Header:=xlYes
        .Offset(, a - 1).Resize(eA + k).ClearContents
    End With
    
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Không sort là di ngược lại căn bản.
Em viết chưa rõ ràng. Đầy đủ là "Không dùng Range.Sort". :)

Cách không dùng Range.Sort có thể là mình lọc và đếm danh sách mã, rồi dựng mảng chỉ số của mỗi mã trong bảng kết quả.
Để tẹo nữa em thử làm xem thế nào.
 
Upvote 0
Bài này làm thủ công bao gồm insert dòng với công thức tính tổng thì chắc cũng vài phút là xong ấy mà
 
Upvote 0
Bài này làm thủ công bao gồm insert dòng với công thức tính tổng thì chắc cũng vài phút là xong ấy mà
Thớt có nói cả gần trăm ngàn dòng. (hổng hiểu GPE có duyên với hàng khủng hay không mà 10 người lên đây hết 9 là khoe hàng khủng)

Đúng ra, đã biết mình chơi hàng khủng thì đáng lẽ phải chịu khó học data model. Microsoft ra cái data model là để phục vụ hàng khủng.
 
Upvote 0
Có danh sách chỉ số dòng rồi, cho vào Union Range là xong luôn. Lúc đó không phải là nhanh nhất mà là siêu nhanh.
Khi nãy OT đã thử làm theo cách này nhưng cũng không được ạ:
Mã:
Public Function TangTocCode(TangToc As Boolean)
    Application.ScreenUpdating = Not (TangToc)
    Application.EnableEvents = Not (TangToc)
    Application.Calculation = IIf(TangToc, xlCalculationManual, xlCalculationAutomatic)
End Function

Sub SumKhongSort()
   
    On Error GoTo End_
   
    Call TangTocCode(True)
   
    Dim Dic As Object, sMa As String, aChuaSum() As Variant, aSumSum() As Variant
    Dim iKey, S, ik&, iSub&, sRow&, r As Long, k As Long, eA As Long, c As Long, a As Long
    Dim rng As Range, RngU As Range, rTam As Range, txtRng As String, txt As String
   
    Const ofset As Integer = 8
    Set rng = Sheet1.Range("A1")
    rng.CurrentRegion.Sort Key1:=rng, Order1:=xlAscending, Header:=xlYes
    aChuaSum = rng.CurrentRegion.Value
    eA = UBound(aChuaSum, 1): a = UBound(aChuaSum, 2)
    If eA < 2 Then Exit Sub
    Set Dic = CreateObject("scripting.dictionary")
    For r = 2 To eA
        sMa = aChuaSum(r, 1)
        If Not Dic.Exists(sMa) Then k = k + 1
        Dic.Item(sMa) = Dic.Item(sMa) & "," & r
    Next r
    sRow = eA + k - 1: k = 0
    ReDim aSumSum(1 To sRow, 1 To a)
    For Each iKey In Dic.Keys
        S = Split(Dic.Item(iKey), ",")
        iSub = k + UBound(S) + 1
        aSumSum(iSub, 1) = "Tong cong: "
        txtRng = "I" & iSub & ":N" & iSub
        If txt = Empty Then
            txt = txtRng
        Else
            txt = txt & "," & txtRng
        End If
        For r = 1 To UBound(S)
            k = k + 1
            ik = CLng(S(r))
            aSumSum(k, 1) = aChuaSum(ik, 1)
            For c = 2 To a
                aSumSum(k, c) = aChuaSum(ik, c)
                aSumSum(iSub, c) = aSumSum(iSub, c) + aChuaSum(ik, c)
            Next c
        Next r
        k = k + 1
    Next iKey
    rng.Offset(, ofset).Resize(, a).Value = rng.Resize(, a).Value
    With rng.Offset(1, ofset)
        .ClearContents
        .Resize(sRow, a) = aSumSum
    End With
    Debug.Print txt
   
   Sheet1.Range(txt).Font.Bold = True

End_:

    Call TangTocCode(False)
   
    If Err.Number <> 0 Then
        MsgBox Err.Description, vbCritical, Err.Number
    Else
        MsgBox "Done!", vbInformation + vbOKOnly
    End If
   
End Sub
Lỗi sau ạ:
1612511507455.png
 
Upvote 0
Thực ra code bài #4 cơ bản (nếu không có dữ liệu thì sẽ có lỗi) đã giải quyết vấn đề. Mọi bài tiếp theo chẳng qua là người ta đố nhau không dùng sort, dùng dic, không dùng dic.

Không sort cũng được nhưng lại phải dùng dic, phải dùng "System.Collections.Hashtable" chứ đâu có phép mầu nào sảy ra? Nếu tôi không lầm thì có người trong system không có class "System.Collections.Hashtable" nên code chạy sẽ có lỗi.
 
Upvote 0
Con cảm ơn Bác @HieuCD đã chỉ dẫn ạ, con biết thêm được cách dùng 'For Each iKey In Dic.keys'
Nhiều lần tôi đã giới thiệu về Dictionary, vd. trong tập tin BC_NXT_2.xlsm ngày 18.12.2019 tôi có viết code trong module
Mã:
Sub BaocaoNXT()
Dim lastRow As Long, r As Long, tungay As Long, denngay As Long, tonKK As Long, count As Long, dvt As String, key, data(), item(), ton As Object, baocao As Object
'    truoc het xoa du lieu cu
    With ThisWorkbook.Worksheets("BC_NXT")
         lastRow = .Cells(Rows.count, "A").End(xlUp).Row
         If lastRow > 9 Then .Range("A10:H" & lastRow).ClearContents
         tungay = .Range("B4").Value
         denngay = .Range("B5").Value
    End With
'    Tinh ton kho cho tung MaH o ngay TON_KHO!H3
    With ThisWorkbook.Worksheets("TON_KHO")
        lastRow = .Cells(Rows.count, "A").End(xlUp).Row
        If lastRow < 7 Then Exit Sub
'        lay du lieu ton vao mang
        data = .Range("A7:J" & lastRow).Value
    End With
'    tu dien co MaH la KEY va mang (soluong, dvt) la ITEM
    Set ton = CreateObject("Scripting.Dictionary")
'    khong phan biet hoa va thuong khi kiem tra MaH
    ton.comparemode = vbTextCompare
'    tu dien baocao co MaH la KEY va mang item la ITEM. mang item = (trongkhoang, tenHH, MaKH, Ton, Tong Nhap, Tong Xuat, Dvt)
    Set baocao = CreateObject("Scripting.Dictionary")
'    khong phan biet hoa va thuong khi kiem tra MaH
    baocao.comparemode = vbTextCompare
'    duyet mang ton kho
    For r = 1 To UBound(data)
        If Not ton.exists(data(r, 1)) Then
            ReDim item(1 To 2)
            item(1) = data(r, 8)
            item(2) = data(r, 10)    ' dvt
            ton.Add data(r, 1), item
        Else
            item = ton.item(data(r, 1))
'            cong don so luong
            item(1) = item(1) + data(r, 8)
'            lam moi item
            ton.item(data(r, 1)) = item
        End If
    Next r
'    duyet sheet THE_KHO
    With ThisWorkbook.Worksheets("THE_KHO")
        lastRow = .Cells(Rows.count, "A").End(xlUp).Row
        If lastRow < 10 Then Exit Sub
'        lay du lieu ton vao mang
        data = .Range("A10:K" & lastRow).Value
    End With
'    duyet mang the kho
    For r = 1 To UBound(data)
        If Not baocao.exists(data(r, 1)) Then
'            neu co ton kiem ke (khong la mat hang moi) thi doc ra tonKK
            If ton.exists(data(r, 1)) Then
                item = ton.item(data(r, 1))
                tonKK = item(1)
                dvt = item(2)
            Else
                tonKK = 0
                dvt = ""
            End If
            ReDim item(1 To 7)
            item(2) = data(r, 2)    ' TenH
            item(3) = data(r, 3)    ' MaKH
            item(4) = tonKK    ' ton hien hanh
            item(7) = dvt   ' dvt
'            them muc voi Ma H vao tu dien baocao
            baocao.Add data(r, 1), item
        Else
            item = baocao.item(data(r, 1))
        End If
        If data(r, 6) < tungay Then
'            muc nam truoc khoang, cong don ton dau
            item(4) = item(4) + data(r, 10) - data(r, 11)
        ElseIf data(r, 6) <= denngay Then
'            muc nam trong khoang
'            danh dau "x" de biet la nam trong khoang
            item(1) = "x"
'            cong don tong Nhap
            item(5) = item(5) + data(r, 10)
'            cong don tong Xuat
            item(6) = item(6) + data(r, 11)
        End If
'        lam moi item
        baocao.item(data(r, 1)) = item
    Next r
'    mang ket qua
    ReDim data(1 To baocao.count, 1 To 8)
    For Each key In baocao.keys
        item = baocao.item(key)
        If item(1) = "x" Then
'            muc nam trong khoang dang xet
            count = count + 1
            data(count, 1) = key ' MaH
            data(count, 2) = item(2)    ' TenH
            data(count, 3) = item(3)    ' MaKH
            data(count, 4) = item(4)    ' Ton dau
            data(count, 5) = item(5)    ' Tong Nhap
            data(count, 6) = item(6)    ' Tong Xuat
            data(count, 7) = item(4) + item(5) - item(6)    ' Ton kho
            data(count, 8) = item(7)    ' dvt
        End If
    Next key
    ThisWorkbook.Worksheets("BC_NXT").Range("A10").Resize(count, 8).Value = data
    
    Set ton = Nothing
    Set baocao = Nothing
End Sub

Rõ ràng có dùng dictionary. Rõ ràng có dùng For Each key In baocao.keys.

Bây giờ đọc đỏ đỏ thì tôi mới biết là mọi ghi chú là không cần thiết vì bạn chỉ dùng code chứ không muốn hiểu và học. Đến bây giờ bạn mới biết cách dùng For Each iKey In Dic.keys
 
Upvote 0
Nhiều lần tôi đã giới thiệu về Dictionary, vd. trong tập tin BC_NXT_2.xlsm ngày 18.12.2019 tôi có viết code trong module
Mã:
Sub BaocaoNXT()
Dim lastRow As Long, r As Long, tungay As Long, denngay As Long, tonKK As Long, count As Long, dvt As String, key, data(), item(), ton As Object, baocao As Object
'    truoc het xoa du lieu cu
    With ThisWorkbook.Worksheets("BC_NXT")
         lastRow = .Cells(Rows.count, "A").End(xlUp).Row
         If lastRow > 9 Then .Range("A10:H" & lastRow).ClearContents
         tungay = .Range("B4").Value
         denngay = .Range("B5").Value
    End With
'    Tinh ton kho cho tung MaH o ngay TON_KHO!H3
    With ThisWorkbook.Worksheets("TON_KHO")
        lastRow = .Cells(Rows.count, "A").End(xlUp).Row
        If lastRow < 7 Then Exit Sub
'        lay du lieu ton vao mang
        data = .Range("A7:J" & lastRow).Value
    End With
'    tu dien co MaH la KEY va mang (soluong, dvt) la ITEM
    Set ton = CreateObject("Scripting.Dictionary")
'    khong phan biet hoa va thuong khi kiem tra MaH
    ton.comparemode = vbTextCompare
'    tu dien baocao co MaH la KEY va mang item la ITEM. mang item = (trongkhoang, tenHH, MaKH, Ton, Tong Nhap, Tong Xuat, Dvt)
    Set baocao = CreateObject("Scripting.Dictionary")
'    khong phan biet hoa va thuong khi kiem tra MaH
    baocao.comparemode = vbTextCompare
'    duyet mang ton kho
    For r = 1 To UBound(data)
        If Not ton.exists(data(r, 1)) Then
            ReDim item(1 To 2)
            item(1) = data(r, 8)
            item(2) = data(r, 10)    ' dvt
            ton.Add data(r, 1), item
        Else
            item = ton.item(data(r, 1))
'            cong don so luong
            item(1) = item(1) + data(r, 8)
'            lam moi item
            ton.item(data(r, 1)) = item
        End If
    Next r
'    duyet sheet THE_KHO
    With ThisWorkbook.Worksheets("THE_KHO")
        lastRow = .Cells(Rows.count, "A").End(xlUp).Row
        If lastRow < 10 Then Exit Sub
'        lay du lieu ton vao mang
        data = .Range("A10:K" & lastRow).Value
    End With
'    duyet mang the kho
    For r = 1 To UBound(data)
        If Not baocao.exists(data(r, 1)) Then
'            neu co ton kiem ke (khong la mat hang moi) thi doc ra tonKK
            If ton.exists(data(r, 1)) Then
                item = ton.item(data(r, 1))
                tonKK = item(1)
                dvt = item(2)
            Else
                tonKK = 0
                dvt = ""
            End If
            ReDim item(1 To 7)
            item(2) = data(r, 2)    ' TenH
            item(3) = data(r, 3)    ' MaKH
            item(4) = tonKK    ' ton hien hanh
            item(7) = dvt   ' dvt
'            them muc voi Ma H vao tu dien baocao
            baocao.Add data(r, 1), item
        Else
            item = baocao.item(data(r, 1))
        End If
        If data(r, 6) < tungay Then
'            muc nam truoc khoang, cong don ton dau
            item(4) = item(4) + data(r, 10) - data(r, 11)
        ElseIf data(r, 6) <= denngay Then
'            muc nam trong khoang
'            danh dau "x" de biet la nam trong khoang
            item(1) = "x"
'            cong don tong Nhap
            item(5) = item(5) + data(r, 10)
'            cong don tong Xuat
            item(6) = item(6) + data(r, 11)
        End If
'        lam moi item
        baocao.item(data(r, 1)) = item
    Next r
'    mang ket qua
    ReDim data(1 To baocao.count, 1 To 8)
    For Each key In baocao.keys
        item = baocao.item(key)
        If item(1) = "x" Then
'            muc nam trong khoang dang xet
            count = count + 1
            data(count, 1) = key ' MaH
            data(count, 2) = item(2)    ' TenH
            data(count, 3) = item(3)    ' MaKH
            data(count, 4) = item(4)    ' Ton dau
            data(count, 5) = item(5)    ' Tong Nhap
            data(count, 6) = item(6)    ' Tong Xuat
            data(count, 7) = item(4) + item(5) - item(6)    ' Ton kho
            data(count, 8) = item(7)    ' dvt
        End If
    Next key
    ThisWorkbook.Worksheets("BC_NXT").Range("A10").Resize(count, 8).Value = data
  
    Set ton = Nothing
    Set baocao = Nothing
End Sub

Rõ ràng có dùng dictionary. Rõ ràng có dùng For Each key In baocao.keys.

Bây giờ đọc đỏ đỏ thì tôi mới biết là mọi ghi chú là không cần thiết vì bạn chỉ dùng code chứ không muốn hiểu và học. Đến bây giờ bạn mới biết cách dùng For Each iKey In Dic.keys
Con chào Bác Siwtom,
Con xin lỗi , dạ code của Bác thì là rất là nhiều có những lúc khi có thời gian con xem và phân tích luôn , nhưng có những lúc bận con chưa xem ngay được và gần như con cũng quên hết mọi việc đến khi có vấn đề gì thay đổi cấu trúc dữ liệu thì con mới xem và phân tích lại ạ.
Công việc trong thời điểm này chuẩn bị nghỉ tết nên con cũng có thời gian khi va chạm đến vấn đề cụ thể thì con mới biết đến ạ.
Bác đã tham gia thì Bác chỉ giúp con lỗi tại bài #32 với ạ.
Con cảm ơn Bác Siwtom,
Chúc Bác nhiều sức khỏe ạ.
 
Lần chỉnh sửa cuối:
Upvote 0
Xin chào anh chị ạ!
Em áp dụng được bài của anh Quang_Hải vào file em rồi, nhưng quy trình của em gồm rất nhiều bước nên sau khi lắp ráp lại thì nó chạy rất là chậm, em treo máy nó chạy khoảng 1,5 giờ.
Em xin gửi file đầy đủ của em lên đây nhờ mấy anh chị em thử, vì em cũng tìm nhiều cách rồi mà nó ko chạy nhanh lên được. Trong file em có sheet mô tả ạ.

Riêng code của bạn NHN_Phương thì hơi quá sức với em nên em chưa áp dụng được, có lẽ vì cách đặt biến khá lạ, nên vừa đọc code vừa nhìn lại biến, đọc một xíu là não em rối nùi luôn :D

File của em ạ: https://drive.google.com/file/d/1_QZLWA5sKYNS8BMHqzii_nmFQPvDhdBK/view?usp=sharing

Cảm ơn anh chị rất nhiều vì đã hỗ trợ em!
 
Upvote 0
Xin chào anh chị ạ!
Em áp dụng được bài của anh Quang_Hải vào file em rồi, nhưng quy trình của em gồm rất nhiều bước nên sau khi lắp ráp lại thì nó chạy rất là chậm, em treo máy nó chạy khoảng 1,5 giờ.
Em xin gửi file đầy đủ của em lên đây nhờ mấy anh chị em thử, vì em cũng tìm nhiều cách rồi mà nó ko chạy nhanh lên được. Trong file em có sheet mô tả ạ.

Riêng code của bạn NHN_Phương thì hơi quá sức với em nên em chưa áp dụng được, có lẽ vì cách đặt biến khá lạ, nên vừa đọc code vừa nhìn lại biến, đọc một xíu là não em rối nùi luôn :D

File của em ạ: https://drive.google.com/file/d/1_QZLWA5sKYNS8BMHqzii_nmFQPvDhdBK/view?usp=sharing

Cảm ơn anh chị rất nhiều vì đã hỗ trợ em!
Ủa vậy hả :"' , OT cũng đang học code nên khai báo các tham số theo mục đích sử dụng nên nó hơi kỳ cục hihi.
 
Upvote 0
Bác đã tham gia thì Bác chỉ giúp con lỗi tại bài #32 với ạ.
Ta xem code
Mã:
For Each iKey In Dic.Keys
        S = Split(Dic.Item(iKey), ",")
        iSub = k + UBound(S) + 1
        aSumSum(iSub, 1) = "Tong cong: "    ' (A)
        txtRng = "I" & iSub & ":N" & iSub    ' (C)
        If txt = Empty Then
            txt = txtRng
        Else
            txt = txt & "," & txtRng
        End If
...
With rng.Offset(1, ofset)
        .ClearContents
        .Resize(sRow, a) = aSumSum    ' (B)
    End With

Sheet1.Range(txt).Font.Bold = True
1. Nhìn vào (A) thì thấy dòng có "Tong cong" là dòng có chỉ số iSub trong mảng aSumSum. Nhìn vào (B) thì thấy mảng aSumSum được đập xuống sheet1 bắt đầu từ I2 (rng.Offset(1, ofset) là I2). Như thế dòng tô đậm có chỉ số iSub trong mảng aSumSum sẽ là dòng có chỉ số trên sheet là (iSub + 1). Nhưng nhìn vào (C) thì thấy địa chỉ của dòng tô mầu được ghi trong biến txt là iSub. Tức tô mầu lệch 1 dòng. Ví dụ 2 Mã đầu giống nhau nên dòng 3 trong mảng sSumSum được tô mầu do là dòng "Tong cong", tức iSub = 3. Từ (C) thấy I3:N3 được ghi vào txt, tức từ (B) thấy là dòng I3:N3 được tô đậm. Trong khi đó dòng tô đậm phải là I4:N4 (dòng 1 là tiêu đề, dòng 2 và 3 là Mã, và phải dòng 4 mới là Tong cong)

2. Sheet1.Range(txt).Font.Bold = True có thể bị lỗi do (đoán mò thôi):
a. chuỗi txt quá dài.
Nếu đúng thế thì thay vì gom hàng mấy chục nghìn địa chỉ vào biến txt thì thử gom hàng mấy chục nghìn vùng ̣(dùng UNION) vào biến Range. Nếu UNION thành công thì cũng có thể thời gian thực hiện là "đi nhậu về mới xong"?
Trong tập tin có 46329 dòng Tong cong

b. Lỗi do gom quá nhiều (hàng mấy chục nghìn) Range. Nếu đúng thế thì chỉ còn nước chia nhỏ thành "vài" nhóm và tô đậm từng nhóm.
 
Upvote 0
Ta xem code
Mã:
For Each iKey In Dic.Keys
        S = Split(Dic.Item(iKey), ",")
        iSub = k + UBound(S) + 1
        aSumSum(iSub, 1) = "Tong cong: "    ' (A)
        txtRng = "I" & iSub & ":N" & iSub    ' (C)
        If txt = Empty Then
            txt = txtRng
        Else
            txt = txt & "," & txtRng
        End If
...
With rng.Offset(1, ofset)
        .ClearContents
        .Resize(sRow, a) = aSumSum    ' (B)
    End With

Sheet1.Range(txt).Font.Bold = True
1. Nhìn vào (A) thì thấy dòng có "Tong cong" là dòng có chỉ số iSub trong mảng aSumSum. Nhìn vào (B) thì thấy mảng aSumSum được đập xuống sheet1 bắt đầu từ I2 (rng.Offset(1, ofset) là I2). Như thế dòng tô đậm có chỉ số iSub trong mảng aSumSum sẽ là dòng có chỉ số trên sheet là (iSub + 1). Nhưng nhìn vào (C) thì thấy địa chỉ của dòng tô mầu được ghi trong biến txt là iSub. Tức tô mầu lệch 1 dòng. Ví dụ 2 Mã đầu giống nhau nên dòng 3 trong mảng sSumSum được tô mầu do là dòng "Tong cong", tức iSub = 3. Từ (C) thấy I3:N3 được ghi vào txt, tức từ (B) thấy là dòng I3:N3 được tô đậm. Trong khi đó dòng tô đậm phải là I4:N4 (dòng 1 là tiêu đề, dòng 2 và 3 là Mã, và phải dòng 4 mới là Tong cong)

2. Sheet1.Range(txt).Font.Bold = True có thể bị lỗi do (đoán mò thôi):
a. chuỗi txt quá dài.
Nếu đúng thế thì thay vì gom hàng mấy chục nghìn địa chỉ vào biến txt thì thử gom hàng mấy chục nghìn vùng ̣(dùng UNION) vào biến Range. Nếu UNION thành công thì cũng có thể thời gian thực hiện là "đi nhậu về mới xong"?
Trong tập tin có 46329 dòng Tong cong

b. Lỗi do gom quá nhiều (hàng mấy chục nghìn) Range. Nếu đúng thế thì chỉ còn nước chia nhỏ thành "vài" nhóm và tô đậm từng nhóm.
Con cảm ơn Bác đã chỉ dẫn ạ.
Vậy là phải tách từng nhóm để tô, lúc nào con thử ạ.
 
Upvote 0
Xin chào anh chị ạ!
Em áp dụng được bài của anh Quang_Hải vào file em rồi, nhưng quy trình của em gồm rất nhiều bước nên sau khi lắp ráp lại thì nó chạy rất là chậm, em treo máy nó chạy khoảng 1,5 giờ.
Em xin gửi file đầy đủ của em lên đây nhờ mấy anh chị em thử, vì em cũng tìm nhiều cách rồi mà nó ko chạy nhanh lên được. Trong file em có sheet mô tả ạ.
Ngay gần đầu, chưa cần đi xa
Mã:
.Range("AL14:AL" & lr) = "=IFERROR(VLOOKUP(B14,PC!B: D,3,0),""Khong xac dinh"")"
    .Range("AM14:AM" & lr) = "=VLOOKUP(B14,shPhu!A: B,2,0)"
Tổng cộng nhập 2*95716 = 191 432 công thức, lại tham chiếu cả cột (B: D, A:B) thì là liều lượng cực khủng. Người ta thường ví như là liều dùng cho ngựa chứ không phải dùng cho người. :D

Bới bèo ra bọ thôi chứ tôi không muốn tham gia.
 
Upvote 0
Web KT
Back
Top Bottom